diff options
Diffstat (limited to 'drivers/video')
47 files changed, 1196 insertions, 658 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a20b7bbee9..9e176d3198 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -31,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" @@ -67,12 +68,6 @@ config DRIVER_VIDEO_STM32_LTDC Say 'Y' here to enable framebuffer and splash screen support for STM32 and STM32MP1. -config DRIVER_VIDEO_S3C24XX - bool "S3C244x framebuffer driver" - depends on ARCH_S3C24xx - help - Add support for the S3C244x LCD controller. - config DRIVER_VIDEO_OMAP bool "OMAP framebuffer driver" depends on ARCH_OMAP4 || COMPILE_TEST @@ -81,13 +76,6 @@ config DRIVER_VIDEO_OMAP 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 @@ -123,6 +111,12 @@ config DRIVER_VIDEO_SIMPLEFB 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 bool "Add EDID support" help @@ -192,4 +186,16 @@ config DRIVER_VIDEO_PANEL_ILITEK_ILI9341 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 9ec0420cca..85cffb5a33 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -11,6 +11,7 @@ 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 @@ -18,13 +19,13 @@ 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_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 diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index 4c05ac5821..0a24493907 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -9,9 +9,9 @@ #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" @@ -260,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 38b4b8df39..5d8dc8f8b9 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -8,7 +8,7 @@ #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> @@ -223,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); } @@ -263,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 110c71bdb2..7aa058e198 100644 --- a/drivers/video/atmel_lcdfb.h +++ b/drivers/video/atmel_lcdfb.h @@ -24,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; @@ -49,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 17f754b566..9d3e6682b6 100644 --- a/drivers/video/atmel_lcdfb_core.c +++ b/drivers/video/atmel_lcdfb_core.c @@ -14,7 +14,7 @@ #include <linux/clk.h> #include <malloc.h> -#include <mach/cpu.h> +#include <mach/at91/cpu.h> #include "atmel_lcdfb.h" @@ -62,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; @@ -237,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) @@ -294,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) { @@ -311,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; @@ -328,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; @@ -378,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; @@ -422,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; @@ -450,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); diff --git a/drivers/video/backlight-pwm.c b/drivers/video/backlight-pwm.c index ffa58c2b2d..87358ca778 100644 --- a/drivers/video/backlight-pwm.c +++ b/drivers/video/backlight-pwm.c @@ -101,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; @@ -164,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); @@ -193,7 +193,7 @@ 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.dev.parent = dev; - pwm_backlight->backlight.node = dev->device_node; + pwm_backlight->backlight.node = dev->of_node; ret = backlight_register(&pwm_backlight->backlight); if (ret) @@ -209,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/bcm2835.c b/drivers/video/bcm2835.c index 14735fe465..070d1b4902 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -15,7 +15,7 @@ #include <xfuncs.h> #include <of_address.h> -#include <mach/mbox.h> +#include <mach/bcm283x/mbox.h> struct bcm2835fb_info { struct fb_info fbi; @@ -54,7 +54,7 @@ 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); @@ -147,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/bochs_hw.c b/drivers/video/bochs/bochs_hw.c index debdd36941..60439ddee5 100644 --- a/drivers/video/bochs/bochs_hw.c +++ b/drivers/video/bochs/bochs_hw.c @@ -8,7 +8,6 @@ #include <common.h> #include <driver.h> -#include <linux/pci.h> #include <fb.h> #include "../edid.h" #include "bochs_hw.h" @@ -149,7 +148,8 @@ static int bochs_hw_read_version(struct bochs *bochs) return ver & 0xF; } -int bochs_hw_probe(struct device_d *dev, void __iomem *fb_map, void __iomem *mmio) +int bochs_hw_probe(struct device *dev, void __iomem *fb_map, + void __iomem *mmio) { struct bochs *bochs; struct fb_info *fb; @@ -157,8 +157,8 @@ int bochs_hw_probe(struct device_d *dev, void __iomem *fb_map, void __iomem *mmi bochs = xzalloc(sizeof(*bochs)); - bochs->fb_map = IOMEM(fb_map); - bochs->mmio = IOMEM(mmio); + bochs->fb_map = fb_map; + bochs->mmio = mmio; ret = bochs_hw_read_version(bochs); if (ret < 0) { diff --git a/drivers/video/bochs/bochs_hw.h b/drivers/video/bochs/bochs_hw.h index 420b58f4da..c721113656 100644 --- a/drivers/video/bochs/bochs_hw.h +++ b/drivers/video/bochs/bochs_hw.h @@ -8,8 +8,8 @@ #define VBE_DISPI_IOPORT_INDEX 0x01CE #define VBE_DISPI_IOPORT_DATA 0x01CF -struct device_d; +struct device; -int bochs_hw_probe(struct device_d *dev, void *fb_map, void __iomem *mmio); +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 index f273ac5f74..50fdecd9c8 100644 --- a/drivers/video/bochs/bochs_isa.c +++ b/drivers/video/bochs/bochs_isa.c @@ -11,7 +11,7 @@ static int bochs_isa_detect(void) { - struct device_d *dev; + struct device *dev; int ret; outw(0, VBE_DISPI_IOPORT_INDEX); @@ -26,6 +26,6 @@ static int bochs_isa_detect(void) if (ret) return ret; - return bochs_hw_probe(dev, (void *)0xe0000000, NULL); + return bochs_hw_probe(dev, IOMEM(0xe0000000), NULL); } device_initcall(bochs_isa_detect); diff --git a/drivers/video/edid.c b/drivers/video/edid.c index 96489f2a37..7e6747ccd5 100644 --- a/drivers/video/edid.c +++ b/drivers/video/edid.c @@ -847,20 +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/efi_gop.c b/drivers/video/efi_gop.c index 5e9bc406e1..cd2506c04b 100644 --- a/drivers/video/efi_gop.c +++ b/drivers/video/efi_gop.c @@ -63,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; diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 1c93dafbc9..6f412d62c4 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -43,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; @@ -158,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; @@ -251,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; @@ -279,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; diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 070378aa23..6c85e8e06a 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -18,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; @@ -60,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 { @@ -122,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) @@ -142,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); } @@ -185,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++; @@ -198,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; } @@ -401,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) { @@ -411,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; } @@ -472,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; @@ -508,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 d158c68c25..e2ff01929b 100644 --- a/drivers/video/imx-ipu-fb.c +++ b/drivers/video/imx-ipu-fb.c @@ -8,14 +8,14 @@ #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 <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> @@ -29,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; @@ -974,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; @@ -1043,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/imx-hdmi.c b/drivers/video/imx-ipu-v3/imx-hdmi.c index d63f2c2111..2d5fd98666 100644 --- a/drivers/video/imx-ipu-v3/imx-hdmi.c +++ b/drivers/video/imx-ipu-v3/imx-hdmi.c @@ -18,8 +18,8 @@ #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" @@ -113,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; @@ -1197,6 +1197,7 @@ static struct of_device_id dw_hdmi_dt_ids[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, dw_hdmi_dt_ids); static int dw_hdmi_get_modes(struct dw_hdmi *hdmi, struct display_timings *timings) { @@ -1248,10 +1249,10 @@ 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; @@ -1347,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-ldb.c b/drivers/video/imx-ipu-v3/imx-ldb.c index 4c934bc72e..3ed6d44f5b 100644 --- a/drivers/video/imx-ipu-v3/imx-ldb.c +++ b/drivers/video/imx-ipu-v3/imx-ldb.c @@ -19,8 +19,8 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/math64.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" @@ -61,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]; @@ -302,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; @@ -403,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 92fa4ed4b4..d8b5f90a6c 100644 --- a/drivers/video/imx-ipu-v3/imx-pd.c +++ b/drivers/video/imx-ipu-v3/imx-pd.c @@ -22,7 +22,7 @@ #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; @@ -61,9 +61,9 @@ static int imx_pd_ioctl(struct vpl *vpl, unsigned int port, 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; @@ -108,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 3d7a19e9c0..4909119d87 100644 --- a/drivers/video/imx-ipu-v3/ipu-common.c +++ b/drivers/video/imx-ipu-v3/ipu-common.c @@ -11,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" @@ -609,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; @@ -705,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, ®->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); @@ -740,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; @@ -844,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 d069d78ab3..a0292fc4a1 100644 --- a/drivers/video/imx-ipu-v3/ipu-dc.c +++ b/drivers/video/imx-ipu-v3/ipu-dc.c @@ -96,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]; }; @@ -312,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 d63613c842..6156911bfc 100644 --- a/drivers/video/imx-ipu-v3/ipu-di.c +++ b/drivers/video/imx-ipu-v3/ipu-di.c @@ -700,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) { diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c index e879f97a33..4be6a15eef 100644 --- a/drivers/video/imx-ipu-v3/ipu-dmfc.c +++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c @@ -100,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; @@ -340,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 67f93c0d55..68b45c11c7 100644 --- a/drivers/video/imx-ipu-v3/ipu-dp.c +++ b/drivers/video/imx-ipu-v3/ipu-dp.c @@ -56,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; @@ -277,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 15aed7a943..4465711ee4 100644 --- a/drivers/video/imx-ipu-v3/ipu-prv.h +++ b/drivers/video/imx-ipu-v3/ipu-prv.h @@ -140,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; @@ -172,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 f8bb69da06..e4ac988053 100644 --- a/drivers/video/imx-ipu-v3/ipufb.c +++ b/drivers/video/imx-ipu-v3/ipufb.c @@ -45,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]; @@ -269,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; @@ -282,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; @@ -305,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; @@ -341,11 +342,11 @@ 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, diff --git a/drivers/video/imx-ipu-v3/ipuv3-plane.c b/drivers/video/imx-ipu-v3/ipuv3-plane.c index a54bdab78b..aed7a46963 100644 --- a/drivers/video/imx-ipu-v3/ipuv3-plane.c +++ b/drivers/video/imx-ipu-v3/ipuv3-plane.c @@ -55,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.c b/drivers/video/imx.c index 615836d47e..cb1c11b4cb 100644 --- a/drivers/video/imx.c +++ b/drivers/video/imx.c @@ -14,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> @@ -150,7 +150,7 @@ struct imxfb_info { unused:30; struct fb_info info; - struct device_d *dev; + struct device *dev; void (*enable)(int enable); @@ -378,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); @@ -525,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; @@ -602,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 index 48b1110f72..9611a402d1 100644 --- a/drivers/video/mipi_dbi.c +++ b/drivers/video/mipi_dbi.c @@ -8,11 +8,13 @@ #define pr_fmt(fmt) "mipi-dbi: " fmt #include <common.h> +#include <dma.h> #include <linux/kernel.h> #include <linux/sizes.h> -#include <gpiod.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> @@ -197,6 +199,220 @@ int mipi_dbi_command_stackbuf(struct mipi_dbi *dbi, u8 cmd, const u8 *data, 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_zalloc(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 * @@ -204,7 +420,7 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf); */ void mipi_dbi_hw_reset(struct mipi_dbi *dbi) { - if (!gpio_is_valid(dbi->reset)) + if (!dbi->reset) return; gpiod_set_value(dbi->reset, 0); @@ -246,6 +462,68 @@ bool mipi_dbi_display_is_on(struct mipi_dbi *dbi) } 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) /** @@ -392,22 +670,21 @@ static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd, * Zero on success, negative error code on failure. */ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi, - int dc) + struct gpio_desc *dc) { - struct device_d *dev = &spi->dev; + struct device *dev = &spi->dev; dbi->spi = spi; dbi->read_commands = mipi_dbi_dcs_read_commands; - if (!gpio_is_valid(dc)) { + if (!dc) { dev_dbg(dev, "MIPI DBI Type-C 1 unsupported\n"); return -ENOSYS; } dbi->command = mipi_dbi_typec3_command; dbi->dc = dc; - // TODO: can we just force 16 bit? - if (mipi_dbi_machine_little_endian() && spi->bits_per_word != 16) + 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); diff --git a/drivers/video/mtl017.c b/drivers/video/mtl017.c index 46c826be21..ba214b47ae 100644 --- a/drivers/video/mtl017.c +++ b/drivers/video/mtl017.c @@ -16,7 +16,7 @@ struct mtl017 { struct vpl vpl; - struct device_d *dev; + struct device *dev; struct i2c_client *client; u8 *regs; int enable_gpio; @@ -218,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); @@ -234,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; @@ -255,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 6fe1e1b08b..74b01239cb 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -37,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; } @@ -46,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; } @@ -90,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; } @@ -99,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 **/ @@ -114,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; } @@ -127,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; } @@ -161,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; } @@ -174,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 189b95d241..3b1ec89c38 100644 --- a/drivers/video/omap.c +++ b/drivers/video/omap.c @@ -27,7 +27,7 @@ struct omapfb_device { struct fb_info info; - struct device_d *dev; + struct device *dev; struct omapfb_display const *cur_display; @@ -410,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; @@ -499,7 +499,7 @@ out: return rc; } -static struct driver_d omapfb_driver = { +static struct driver omapfb_driver = { .name = "omap_fb", .probe = omapfb_probe, }; diff --git a/drivers/video/panel-ilitek-ili9341.c b/drivers/video/panel-ilitek-ili9341.c index d877442022..4d03a8513e 100644 --- a/drivers/video/panel-ilitek-ili9341.c +++ b/drivers/video/panel-ilitek-ili9341.c @@ -12,10 +12,10 @@ * * Derived from Linux drivers/drm/gpu/panel/panel-ilitek-ili9341.c */ -#define DEBUG 1 + #include <common.h> #include <linux/bitops.h> -#include <gpiod.h> +#include <linux/gpio/consumer.h> #include <of.h> #include <regulator.h> #include <spi/spi.h> @@ -159,11 +159,11 @@ struct ili9341_config { }; struct ili9341 { - struct device_d *dev; + struct device *dev; struct vpl vpl; const struct ili9341_config *conf; - int reset_gpio; - int dc_gpio; + struct gpio_desc *reset_gpio; + struct gpio_desc *dc_gpio; struct mipi_dbi *dbi; u32 max_spi_speed; struct regulator_bulk_data supplies[3]; @@ -280,7 +280,7 @@ static inline struct ili9341 *vpl_to_ili9341(struct vpl *vpl) static void ili9341_dpi_init(struct ili9341 *ili) { - struct device_d *dev = ili->dev; + struct device *dev = ili->dev; struct mipi_dbi *dbi = ili->dbi; struct ili9341_config *cfg = (struct ili9341_config *)ili->conf; @@ -344,7 +344,7 @@ static void ili9341_dpi_init(struct ili9341 *ili) static int ili9341_dpi_power_on(struct ili9341 *ili) { - struct device_d *dev = ili->dev; + struct device *dev = ili->dev; int ret = 0; /* Assert RESET */ @@ -458,9 +458,10 @@ static int ili9341_ioctl(struct vpl *vpl, unsigned int port, } } -static int ili9341_dpi_probe(struct spi_device *spi, int dc, int reset) +static int ili9341_dpi_probe(struct spi_device *spi, + struct gpio_desc *dc, struct gpio_desc *reset) { - struct device_d *dev = &spi->dev; + struct device *dev = &spi->dev; struct ili9341 *ili; int ret; @@ -499,23 +500,23 @@ static int ili9341_dpi_probe(struct spi_device *spi, int dc, int reset) ili->dev = dev; ili->max_spi_speed = ili->conf->max_spi_speed; - ili->vpl.node = dev->device_node; + ili->vpl.node = dev->of_node; ili->vpl.ioctl = ili9341_ioctl; return vpl_register(&ili->vpl); } -static int ili9341_probe(struct device_d *dev) +static int ili9341_probe(struct device *dev) { struct spi_device *spi = to_spi_device(dev); - int dc, reset; + struct gpio_desc *dc, *reset; - reset = gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (!gpio_is_valid(reset) && reset != -ENOENT) + 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 (!gpio_is_valid(dc) && dc != -ENOENT) + if (IS_ERR(dc)) dev_err(dev, "Failed to get gpio 'dc'\n"); return ili9341_dpi_probe(spi, dc, reset); @@ -528,8 +529,9 @@ static const struct of_device_id ili9341_of_match[] = { }, { } }; +MODULE_DEVICE_TABLE(of, ili9341_of_match); -static struct driver_d ili9341_driver = { +static struct driver ili9341_driver = { .name = "panel-ilitek-ili9341", .of_compatible = ili9341_of_match, .probe = ili9341_probe, 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 7e2905f279..561a73fb32 100644 --- a/drivers/video/pxa.c +++ b/drivers/video/pxa.c @@ -23,10 +23,10 @@ #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 <linux/math64.h> @@ -74,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); @@ -476,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; @@ -534,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 ca6c5aa3e3..360b27eebb 100644 --- a/drivers/video/rave-sp-backlight.c +++ b/drivers/video/rave-sp-backlight.c @@ -27,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; @@ -52,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 6de2d7be98..0000000000 --- a/drivers/video/s3c24xx.c +++ /dev/null @@ -1,411 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * 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> - */ - -#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; - - fbi.info.dev.parent = hw_dev; - 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 28a41916eb..06e13b7735 100644 --- a/drivers/video/sdl.c +++ b/drivers/video/sdl.c @@ -38,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; @@ -81,7 +81,7 @@ static int sdlfb_probe(struct device_d *dev) return ret; } -static void sdlfb_remove(struct device_d *dev) +static void sdlfb_remove(struct device *dev) { struct fb_info *fb = dev->priv; @@ -89,7 +89,7 @@ static void sdlfb_remove(struct device_d *dev) kfree(fb); } -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 a87adcca64..7048e2f51b 100644 --- a/drivers/video/simple-panel.c +++ b/drivers/video/simple-panel.c @@ -17,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; @@ -99,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; @@ -129,10 +129,10 @@ static int simple_panel_ioctl(struct vpl *vpl, unsigned int port, } } -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; @@ -165,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 index 2367713ba4..dafec6178f 100644 --- a/drivers/video/simplefb-client.c +++ b/drivers/video/simplefb-client.c @@ -35,10 +35,10 @@ struct simplefb { struct fb_videomode mode; }; -static int simplefb_parse_dt(struct device_d *dev, - struct simplefb_params *params) +static int simplefb_parse_dt(struct device *dev, + struct simplefb_params *params) { - struct device_node *np = dev->device_node; + struct device_node *np = dev->of_node; int ret; const char *format; int i; @@ -81,7 +81,7 @@ static int simplefb_parse_dt(struct device_d *dev, return 0; } -static int simplefb_probe(struct device_d *dev) +static int simplefb_probe(struct device *dev) { int ret; struct simplefb_params params; @@ -90,7 +90,7 @@ static int simplefb_probe(struct device_d *dev) struct resource *mem; ret = -ENODEV; - if (dev->device_node) + if (dev->of_node) ret = simplefb_parse_dt(dev, ¶ms); if (ret) @@ -138,8 +138,9 @@ static const struct of_device_id simplefb_of_match[] = { { .compatible = "simple-framebuffer", }, { }, }; +MODULE_DEVICE_TABLE(of, simplefb_of_match); -static struct driver_d simplefb_driver = { +static struct driver simplefb_driver = { .name = "simple-framebuffer", .of_compatible = simplefb_of_match, .probe = simplefb_probe, diff --git a/drivers/video/simplefb-fixup.c b/drivers/video/simplefb-fixup.c index a2c59de364..65e0281a18 100644 --- a/drivers/video/simplefb-fixup.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 9e141a851f..fb50e895c5 100644 --- a/drivers/video/ssd1307fb.c +++ b/drivers/video/ssd1307fb.c @@ -423,13 +423,14 @@ static const struct of_device_id ssd1307fb_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, ssd1307fb_of_match); -static int ssd1307fb_probe(struct device_d *dev) +static int ssd1307fb_probe(struct device *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; @@ -451,12 +452,12 @@ static int ssd1307fb_probe(struct device_d *dev) par->device_info = (struct ssd1307fb_deviceinfo *)match->data; - if (IS_ENABLED(CONFIG_I2C) && dev->bus == &i2c_bus) { + 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 (IS_ENABLED(CONFIG_SPI) && dev->bus == &spi_bus) { + 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)) { @@ -634,14 +635,14 @@ fb_alloc_error: return ret; } -static __maybe_unused struct driver_d ssd1307fb_i2c_driver = { +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_d ssd1307fb_spi_driver = { +static __maybe_unused struct driver ssd1307fb_spi_driver = { .name = "ssd1307fb-spi", .probe = ssd1307fb_probe, .of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match), diff --git a/drivers/video/stm.c b/drivers/video/stm.c index 14182f8c46..917405ea80 100644 --- a/drivers/video/stm.c +++ b/drivers/video/stm.c @@ -20,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) @@ -139,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; @@ -494,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; @@ -532,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; @@ -581,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 index 9dc35ade61..d1c36b1f45 100644 --- a/drivers/video/stm32_ltdc.c +++ b/drivers/video/stm32_ltdc.c @@ -21,7 +21,7 @@ struct ltdc_hw { void __iomem *regs; - struct device_d *dev; + struct device *dev; struct clk *pclk; bool claimed; }; @@ -252,7 +252,7 @@ static struct fb_ops ltdc_ops = { .fb_disable = ltdc_disable, }; -static int ltdc_probe(struct device_d *dev) +static int ltdc_probe(struct device *dev) { struct device_node *np; struct resource *iores; @@ -273,7 +273,7 @@ static int ltdc_probe(struct device_d *dev) return PTR_ERR(hw->pclk); } - for_each_available_child_of_node(dev->device_node, np) { + for_each_available_child_of_node(dev->of_node, np) { struct ltdc_fb *priv; struct of_endpoint ep; struct fb_info *info; @@ -285,12 +285,12 @@ static int ltdc_probe(struct device_d *dev) if (ret) return ret; - dev_dbg(hw->dev, "register vpl for %s\n", np->full_name); + 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->device_node; + priv->vpl.node = dev->of_node; ret = vpl_register(&priv->vpl); if (ret) @@ -327,8 +327,9 @@ static __maybe_unused struct of_device_id ltdc_ids[] = { { .compatible = "st,stm32-ltdc" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, ltdc_ids); -static struct driver_d ltdc_driver = { +static struct driver ltdc_driver = { .name = "stm32-ltdc", .probe = ltdc_probe, .of_compatible = DRV_OF_COMPAT(ltdc_ids), diff --git a/drivers/video/tc358767.c b/drivers/video/tc358767.c index 36f4125414..da106496fc 100644 --- a/drivers/video/tc358767.c +++ b/drivers/video/tc358767.c @@ -204,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; @@ -880,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; @@ -1334,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; @@ -1347,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; @@ -1371,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); @@ -1410,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); @@ -1419,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 f94bd4a3e2..f8c2159cd9 100644 --- a/drivers/video/vpl.c +++ b/drivers/video/vpl.c @@ -18,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; } @@ -40,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); } @@ -57,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; } @@ -72,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; } @@ -89,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; |