[PATCH v5] omap4-fb: add driver

Jean-Christophe PLAGNIOL-VILLARD plagnioj at jcrosoft.com
Fri Jun 14 07:43:12 EDT 2013


On 10:15 Fri 14 Jun     , Christoph Fritz wrote:
> This patch adds omap4 display controller support.
> 
> Signed-off-by: Christoph Fritz <chf.fritz at googlemail.com>
> ---
> changes since v2:
>         - use dev_request_mem_region_by_name()
> changes since v3:
>         - remove register struct
>         - use uncached screen_base
> changes since v4:
>         - remove useless dev_add_param()
>         - use wait_on_timeout() instead while-deadlock
> ---
>  arch/arm/mach-omap/Makefile                |    1 +
>  arch/arm/mach-omap/include/mach/omap4-fb.h |   46 +++
>  arch/arm/mach-omap/omap4_fb.c              |   27 ++

Sasha will device but for me this is 2 patches

1 for the driver
1 for the mach-omap
>  drivers/video/Kconfig                      |    8 +
>  drivers/video/Makefile                     |    1 +
>  drivers/video/omap4.c                      |  527 ++++++++++++++++++++++++++++
>  drivers/video/omap4.h                      |  181 ++++++++++
>  7 files changed, 791 insertions(+)
>  create mode 100644 arch/arm/mach-omap/include/mach/omap4-fb.h
>  create mode 100644 arch/arm/mach-omap/omap4_fb.c
>  create mode 100644 drivers/video/omap4.c
>  create mode 100644 drivers/video/omap4.h
> 
> diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
> index 94e42c6..e70ddbd 100644
> --- a/arch/arm/mach-omap/Makefile
> +++ b/arch/arm/mach-omap/Makefile
> @@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock.o
>  pbl-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock.o
>  obj-$(CONFIG_OMAP_GPMC) += gpmc.o devices-gpmc-nand.o
>  obj-$(CONFIG_SHELL_NONE) += xload.o
> +obj-$(CONFIG_DRIVER_VIDEO_OMAP4) += omap4_fb.o
>  obj-$(CONFIG_I2C_TWL6030) += omap4_twl6030_mmc.o
>  obj-$(CONFIG_OMAP4_USBBOOT) += omap4_rom_usb.o
>  obj-y += gpio.o
> diff --git a/arch/arm/mach-omap/include/mach/omap4-fb.h b/arch/arm/mach-omap/include/mach/omap4-fb.h
> new file mode 100644
> index 0000000..5c0a54b
> --- /dev/null
> +++ b/arch/arm/mach-omap/include/mach/omap4-fb.h
> @@ -0,0 +1,46 @@
> +#ifndef H_BAREBOX_ARCH_ARM_MACH_OMAP_MACH_FB4_H
> +#define H_BAREBOX_ARCH_ARM_MACH_OMAP_MACH_FB4_H
> +
> +#include <fb.h>
> +
> +#define OMAP_DSS_LCD_TFT	(1u << 0)
> +#define OMAP_DSS_LCD_IVS	(1u << 1)
> +#define OMAP_DSS_LCD_IHS	(1u << 2)
> +#define OMAP_DSS_LCD_IPC	(1u << 3)
> +#define OMAP_DSS_LCD_IEO	(1u << 4)
> +#define OMAP_DSS_LCD_RF	(1u << 5)
> +#define OMAP_DSS_LCD_ONOFF	(1u << 6)
> +
> +#define OMAP_DSS_LCD_DATALINES(_l)	((_l) << 10)
> +#define OMAP_DSS_LCD_DATALINES_msk	OMAP_DSS_LCD_DATALINES(3u)
> +#define OMAP_DSS_LCD_DATALINES_12	OMAP_DSS_LCD_DATALINES(0u)
> +#define OMAP_DSS_LCD_DATALINES_16	OMAP_DSS_LCD_DATALINES(1u)
> +#define OMAP_DSS_LCD_DATALINES_18	OMAP_DSS_LCD_DATALINES(2u)
> +#define OMAP_DSS_LCD_DATALINES_24	OMAP_DSS_LCD_DATALINES(3u)
> +
> +struct omap4fb_display {
> +	struct fb_videomode mode;
> +
> +	unsigned long config;
> +
> +	unsigned int power_on_delay;
> +	unsigned int power_off_delay;
> +};
> +
> +struct omap4fb_platform_data {
> +	struct omap4fb_display const *displays;
> +	size_t num_displays;
> +
> +	unsigned int dss_clk_hz;
> +
> +	unsigned int bpp;
> +
> +	struct resource const *screen;
> +
> +	void (*enable)(int p);
> +};
> +
> +struct device_d;
> +struct device_d *omap4_add_display(void *pdata);
> +
> +#endif	/* H_BAREBOX_ARCH_ARM_MACH_OMAP_MACH_FB4_H */
> diff --git a/arch/arm/mach-omap/omap4_fb.c b/arch/arm/mach-omap/omap4_fb.c
> new file mode 100644
> index 0000000..09a6af3
> --- /dev/null
> +++ b/arch/arm/mach-omap/omap4_fb.c
> @@ -0,0 +1,27 @@
> +#include <driver.h>
> +#include <common.h>
> +#include <linux/ioport.h>
> +#include <mach/omap4-fb.h>
> +
> +static struct resource omap4_fb_resources[] = {
> +	{
> +		.name	= "omap4_dss",
> +		.start	= 0x48040000,
> +		.end	= 0x48040000 + 512 - 1,
> +		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
> +	}, {
> +		.name	= "omap4_dispc",
> +		.start	= 0x48041000,
> +		.end	= 0x48041000 + 3072 - 1,
> +		.flags	= IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
> +	},
> +};
> +
> +struct device_d *omap4_add_display(void *pdata)
> +{
> +	return add_generic_device_res("omap4_fb", -1,
> +				      omap4_fb_resources,
> +				      ARRAY_SIZE(omap4_fb_resources),
> +				      pdata);
> +}
> +EXPORT_SYMBOL(omap4_add_display);
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 6d6b08f..9dfa0cd 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -45,6 +45,14 @@ config DRIVER_VIDEO_S3C24XX
>  	help
>  	  Add support for the S3C244x LCD controller.
>  
> +config DRIVER_VIDEO_OMAP4
> +	bool "OMAP4 framebuffer driver"
> +	depends on ARCH_OMAP4
> +	help
> +	  Add support for the OMAP4 Display Controller.
> +	  DSI is unsupported, only DISPC parallel mode on LCD2
> +	  is supported.
> +
>  if DRIVER_VIDEO_S3C24XX
>  
>  config DRIVER_VIDEO_S3C_VERBOSE
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 7429141..83feebb 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -8,3 +8,4 @@ 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_OMAP4) += omap4.o
> diff --git a/drivers/video/omap4.c b/drivers/video/omap4.c
> new file mode 100644
> index 0000000..a7c6253
> --- /dev/null
> +++ b/drivers/video/omap4.c
> @@ -0,0 +1,527 @@
> +/*
> + * TI Omap4 Frame Buffer device driver
> + *
> + * Copyright (C) 2013 Christoph Fritz <chf.fritz at googlemail.com>
> + *   Based on work by Enrico Scholz, sponsored by Phytec
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <driver.h>
> +#include <fb.h>
> +#include <errno.h>
> +#include <xfuncs.h>
> +#include <init.h>
> +#include <stdio.h>
> +#include <io.h>
> +#include <common.h>
> +#include <malloc.h>
> +#include <common.h>
> +#include <clock.h>
> +
> +#include <mach/omap4-silicon.h>
> +#include <mach/omap4-fb.h>
> +
> +#include <asm/mmu.h>
> +
> +#include "omap4.h"
> +
> +struct omap4fb_device {
> +	struct fb_info info;
> +	struct device_d *dev;
> +
> +	struct omap4fb_display const *cur_display;
> +
> +	struct omap4fb_display const *displays;
> +	size_t num_displays;
> +
> +	void __iomem *dss;
> +	void __iomem *dispc;
> +
> +	struct {
> +		void __iomem *addr;
> +		size_t size;
> +	} prealloc_screen;
> +
> +	struct {
> +		uint32_t dispc_control;
> +		uint32_t dispc_pol_freq;
> +	} shadow;
> +
> +	struct {
> +		unsigned int dss_clk_hz;
> +		unsigned int lckd;
> +		unsigned int pckd;
> +	} divisor;
> +	size_t dma_size;
> +	void (*enable_fn)(int);
> +
> +	struct fb_videomode	video_modes[];
> +};
> +
> +static void omap4fb_enable(struct fb_info *info)
> +{
> +	struct omap4fb_device *fbi =
> +		container_of(info, struct omap4fb_device, info);
> +
> +	dev_info(fbi->dev, "%s\n", __func__);
dev_dbg

no need verbose for nornal operation
> +
> +	if (!fbi->cur_display) {
> +		dev_err(fbi->dev, "no valid mode set\n");
> +		return;
> +	}
> +
> +	if (fbi->enable_fn)
> +		fbi->enable_fn(1);
> +
> +	udelay(fbi->cur_display->power_on_delay * 1000u);
> +
> +	fb_write(fb_read(fbi->dispc, O4_DISPC_CONTROL2) |
> +		 DSS_DISPC_CONTROL_LCDENABLE |
> +		 DSS_DISPC_CONTROL_LCDENABLESIGNAL,
> +		 fbi->dispc, O4_DISPC_CONTROL2);
> +
> +	fb_write(fb_read(fbi->dispc, O4_DISPC_VID1_ATTRIBUTES) |
> +		 DSS_DISPC_VIDn_ATTRIBUTES_VIDENABLE,
> +		 fbi->dispc, O4_DISPC_VID1_ATTRIBUTES);
> +
> +	fb_write(fb_read(fbi->dispc, O4_DISPC_CONTROL2) |
> +		 DSS_DISPC_CONTROL_GOLCD,
> +		 fbi->dispc, O4_DISPC_CONTROL2);
> +}
> +
> +static void omap4fb_disable(struct fb_info *info)
> +{
> +	struct omap4fb_device	*fbi =
> +		container_of(info, struct omap4fb_device, info);
> +
> +	dev_info(fbi->dev, "%s\n", __func__);
ditto
> +
> +	if (!fbi->cur_display) {
> +		dev_err(fbi->dev, "no valid mode set\n");
> +		return;
> +	}
> +
> +	fb_write(fb_read(fbi->dispc, O4_DISPC_CONTROL2) &
> +		~(DSS_DISPC_CONTROL_LCDENABLE |
> +		DSS_DISPC_CONTROL_LCDENABLESIGNAL),
> +		fbi->dispc, O4_DISPC_CONTROL2);
> +
> +	fb_write(fb_read(fbi->dispc, O4_DISPC_VID1_ATTRIBUTES) &
> +		 ~(DSS_DISPC_VIDn_ATTRIBUTES_VIDENABLE),
> +		 fbi->dispc, O4_DISPC_VID1_ATTRIBUTES);
> +
> +	if (fbi->prealloc_screen.addr == NULL) {
> +		/* free frame buffer; but only when screen is not
> +		 * preallocated */
> +		if (info->screen_base)
> +			dma_free_coherent(info->screen_base, fbi->dma_size);
> +	}
> +
> +	info->screen_base = NULL;
> +
> +	udelay(fbi->cur_display->power_off_delay * 1000u);
> +
> +	if (fbi->enable_fn)
> +		fbi->enable_fn(0);
> +}
> +
> +static void omap4fb_calc_divisor(struct omap4fb_device *fbi,
> +			struct fb_videomode const *mode)
> +{
> +	unsigned int l, k, t, b;
> +
> +	b = UINT_MAX;
> +	for (l = 1; l < 256; l++) {
> +		for (k = 1; k < 256; k++) {
> +			t = abs(mode->pixclock * 100 -
> +				(fbi->divisor.dss_clk_hz / l / k));
> +			if (t <= b) {
> +				b = t;
> +				fbi->divisor.lckd = l;
> +				fbi->divisor.pckd = k;
> +			}
> +		}
> +	}
> +}
> +
> +static unsigned int omap4fb_calc_format(struct fb_info const *info)
> +{
> +	switch (info->bits_per_pixel) {
> +	case 24: return 9;
	case x:
		return
> +	case 32: return 0x8; /* xRGB24-8888 (32-bit container) */
> +	default:
> +		printf("%s: unsupported bpp %d\n", __func__,
dev_err
> +		       info->bits_per_pixel);
> +		return 0;
> +	}
> +}
> +
> +struct omap4fb_colors {
> +	struct fb_bitfield	red;
> +	struct fb_bitfield	green;
> +	struct fb_bitfield	blue;
> +	struct fb_bitfield	transp;
> +};
> +
> +static struct omap4fb_colors const omap4fb_col[] = {
> +	[0] = {
> +		.red	= { .length = 0, .offset = 0 },
> +	},
> +	[1] = {
> +		.blue	= { .length = 8, .offset = 0 },
> +		.green	= { .length = 8, .offset = 8 },
> +		.red	= { .length = 8, .offset = 16 },
> +	},
> +	[2] = {
> +		.blue	= { .length = 8, .offset = 0 },
> +		.green	= { .length = 8, .offset = 8 },
> +		.red	= { .length = 8, .offset = 16 },
> +		.transp	= { .length = 8, .offset = 24 },
> +	},
> +};
> +
> +static void omap4fb_fill_shadow(struct omap4fb_device *fbi,
> +				struct omap4fb_display const *display)
> +{
> +	fbi->shadow.dispc_control = 0;
> +	fbi->shadow.dispc_pol_freq = 0;
> +
> +	fbi->shadow.dispc_control |= DSS_DISPC_CONTROL_STNTFT;
> +
> +	switch (display->config & OMAP_DSS_LCD_DATALINES_msk) {
> +	case OMAP_DSS_LCD_DATALINES_12:
> +		fbi->shadow.dispc_control |= DSS_DISPC_CONTROL_TFTDATALINES_12;
> +		break;
> +	case OMAP_DSS_LCD_DATALINES_16:
> +		fbi->shadow.dispc_control |= DSS_DISPC_CONTROL_TFTDATALINES_16;
> +		break;
> +	case OMAP_DSS_LCD_DATALINES_18:
> +		fbi->shadow.dispc_control |= DSS_DISPC_CONTROL_TFTDATALINES_18;
> +		break;
> +	case OMAP_DSS_LCD_DATALINES_24:
> +		fbi->shadow.dispc_control |= DSS_DISPC_CONTROL_TFTDATALINES_24;
> +		break;
> +	}
> +
> +	if (display->config & OMAP_DSS_LCD_IPC)
> +		fbi->shadow.dispc_pol_freq |= DSS_DISPC_POL_FREQ_IPC;
> +
> +	if (display->config & OMAP_DSS_LCD_IVS)
> +		fbi->shadow.dispc_pol_freq |= DSS_DISPC_POL_FREQ_IVS;
> +
> +	if (display->config & OMAP_DSS_LCD_IHS)
> +		fbi->shadow.dispc_pol_freq |= DSS_DISPC_POL_FREQ_IHS;
> +
> +	if (display->config & OMAP_DSS_LCD_IEO)
> +		fbi->shadow.dispc_pol_freq |= DSS_DISPC_POL_FREQ_IEO;
> +
> +	if (display->config & OMAP_DSS_LCD_RF)
> +		fbi->shadow.dispc_pol_freq |= DSS_DISPC_POL_FREQ_RF;
> +
> +	if (display->config & OMAP_DSS_LCD_ONOFF)
> +		fbi->shadow.dispc_pol_freq |= DSS_DISPC_POL_FREQ_ONOFF;
> +}
> +
> +static int omap4fb_activate_var(struct fb_info *info)
> +{
> +	struct omap4fb_device *fbi =
> +		container_of(info, struct omap4fb_device, info);
> +	struct fb_videomode const *mode = info->mode;
> +	size_t size = mode->xres * mode->yres * (info->bits_per_pixel / 8);
> +	int rc;
> +	unsigned int fmt = omap4fb_calc_format(info);
> +	struct omap4fb_colors const *cols;
> +	size_t i;
> +	struct omap4fb_display const *new_display = NULL;
> +
> +	for (i = 0; i < fbi->num_displays && new_display == NULL; ++i) {
> +		if (strcmp(mode->name, fbi->displays[i].mode.name) == 0)
> +			new_display = &fbi->displays[i];
> +	}
do this search in a function and return
> +
> +	if (WARN_ON(!new_display)) {
> +		dev_err(fbi->dev, "no display found for this mode '%s'\n",
> +			mode->name);
> +		rc = -ENXIO;
> +		goto out;
> +	}
> +
> +	/*Free old screen buf*/
> +	if (!fbi->prealloc_screen.addr && info->screen_base)
> +		dma_free_coherent(info->screen_base, fbi->dma_size);
> +
> +	fbi->dma_size = PAGE_ALIGN(size);
> +
> +	if (fbi->prealloc_screen.addr == NULL) {
consistant !xxx
> +		/* case 1: no preallocated screen */
> +		info->screen_base = dma_alloc_coherent(size);
> +	} else if (fbi->prealloc_screen.size < fbi->dma_size) {
> +		/* case 2: preallocated screen, but too small */
> +		dev_err(fbi->dev,
> +			"allocated framebuffer too small (%zu < %zu)\n",
> +			fbi->prealloc_screen.size, fbi->dma_size);
> +		rc = -ENOMEM;
> +		goto out;
> +	} else {
> +		/* case 3: preallocated screen */
> +		info->screen_base = fbi->prealloc_screen.addr;
> +	}
> +
> +	omap4fb_fill_shadow(fbi, new_display);
> +
> +	omap4fb_calc_divisor(fbi, mode);
> +
> +	switch (info->bits_per_pixel) {
> +	case 24:
> +		cols = &omap4fb_col[1];
> +		break;
> +	case 32:
> +		cols = &omap4fb_col[2];
> +		break;
> +	default:
> +		cols = &omap4fb_col[0];
> +	}
> +
> +	info->red = cols->red;
> +	info->green = cols->green;
> +	info->blue = cols->blue;
> +	info->transp = cols->transp;
> +
> +	fb_write(fbi->shadow.dispc_control,
> +		 fbi->dispc, O4_DISPC_CONTROL2);
> +
> +	fb_write(fbi->shadow.dispc_pol_freq,
> +			fbi->dispc, O4_DISPC_POL_FREQ2);
> +
> +	fb_write(DSS_DISPC_TIMING_H_HSW(mode->hsync_len - 1) |
> +		 DSS_DISPC_TIMING_H_HFP(mode->right_margin - 1) |
> +		 DSS_DISPC_TIMING_H_HBP(mode->left_margin - 1),
> +		 fbi->dispc, O4_DISPC_TIMING_H2);
> +
> +	fb_write(DSS_DISPC_TIMING_V_VSW(mode->vsync_len - 1) |
> +		 DSS_DISPC_TIMING_V_VFP(mode->lower_margin) |
> +		 DSS_DISPC_TIMING_V_VBP(mode->upper_margin),
> +		 fbi->dispc, O4_DISPC_TIMING_V2);
> +
> +	fb_write(DSS_DISPC_DIVISOR_ENABLE | DSS_DISPC_DIVISOR_LCD(1),
> +			fbi->dispc, O4_DISPC_DIVISOR);
> +
> +	fb_write(DSS_DISPC_DIVISOR2_LCD(fbi->divisor.lckd) |
> +		 DSS_DISPC_DIVISOR2_PCD(fbi->divisor.pckd),
> +		 fbi->dispc, O4_DISPC_DIVISOR2);
> +
> +	fb_write(DSS_DISPC_SIZE_LCD_PPL(mode->xres - 1) |
> +		 DSS_DISPC_SIZE_LCD_LPP(mode->yres - 1),
> +		 fbi->dispc, O4_DISPC_SIZE_LCD2);
> +
> +	fb_write(0x0000ff00, fbi->dispc, O4_DISPC_DEFAULT_COLOR2);
> +
> +	/* we use VID1 */
> +	fb_write((uintptr_t)info->screen_base, fbi->dispc, O4_DISPC_VID1_BA0);
> +	fb_write((uintptr_t)info->screen_base, fbi->dispc, O4_DISPC_VID1_BA1);
> +
> +	fb_write(DSS_DISPC_VIDn_POSITION_VIDPOSX(0) |
> +		 DSS_DISPC_VIDn_POSITION_VIDPOSY(0),
> +		 fbi->dispc, O4_DISPC_VID1_POSITION);
> +	fb_write(DSS_DISPC_VIDn_SIZE_VIDSIZEX(mode->xres - 1) |
> +		 DSS_DISPC_VIDn_SIZE_VIDSIZEY(mode->yres - 1),
> +		 fbi->dispc, O4_DISPC_VID1_SIZE);
> +	fb_write(DSS_DISPC_VIDn_PICTURE_SIZE_VIDORGSIZEX(mode->xres - 1) |
> +		 DSS_DISPC_VIDn_PICTURE_SIZE_VIDORGSIZEY(mode->yres - 1),
> +		 fbi->dispc, O4_DISPC_VID1_PICTURE_SIZE);
> +	fb_write(1, fbi->dispc, O4_DISPC_VID1_ROW_INC);
> +	fb_write(1, fbi->dispc, O4_DISPC_VID1_PIXEL_INC);
> +
> +	fb_write(0xfff, fbi->dispc, O4_DISPC_VID1_PRELOAD);
> +
> +	fb_write(DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(fmt) |
> +			 DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE_8x128 |
> +			 DSS_DISPC_VIDn_ATTRIBUTES_ZORDERENABLE |
> +			 DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2_SECONDARY_LCD,
> +			 fbi->dispc, O4_DISPC_VID1_ATTRIBUTES);
> +
> +	rc = wait_on_timeout(O4_TIMEOUT,
> +		!(fb_read(fbi->dispc, O4_DISPC_CONTROL2) &
> +		DSS_DISPC_CONTROL_GOLCD));
> +
> +	if (rc) {
> +		dev_err(fbi->dev, "timeout: dispc golcd\n");
> +		goto out;
> +	}
> +
> +	fb_write(fb_read(fbi->dispc, O4_DISPC_CONTROL2) |
> +		 DSS_DISPC_CONTROL_GOLCD,
> +		 fbi->dispc, O4_DISPC_CONTROL2);
> +
> +	fbi->cur_display = new_display;
> +	info->xres = mode->xres;
> +	info->yres = mode->yres;
> +
> +	rc = 0;
> +
> +out:
> +	return rc;
> +}
> +
> +static int omap4fb_reset(struct omap4fb_device const *fbi)
> +{
> +	uint32_t v = fb_read(fbi->dispc, O4_DISPC_CONTROL2);
> +	int rc;
> +
> +	/* step 1: stop the LCD controller */
> +	if (v & DSS_DISPC_CONTROL_LCDENABLE) {
> +		fb_write(v & ~DSS_DISPC_CONTROL_LCDENABLE,
> +				fbi->dispc, O4_DISPC_CONTROL2);
> +
> +		fb_write(DSS_DISPC_IRQSTATUS_FRAMEDONE2, fbi->dispc,
> +			O4_DISPC_IRQSTATUS);
> +
> +
> +		rc = wait_on_timeout(O4_TIMEOUT,
> +			((fb_read(fbi->dispc, O4_DISPC_IRQSTATUS) &
> +			DSS_DISPC_IRQSTATUS_FRAMEDONE) != 0));
> +
> +		if (rc) {
> +			dev_err(fbi->dev, "timeout: irqstatus framedone\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +
> +	/* step 2: wait for reset done status */
> +	rc = wait_on_timeout(O4_TIMEOUT,
> +		(fb_read(fbi->dss, O4_DSS_SYSSTATUS) &
> +		DSS_DSS_SYSSTATUS_RESETDONE));
> +
> +	if (rc) {
> +		dev_err(fbi->dev, "timeout: sysstatus resetdone\n");
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* DSS_CTL: set to reset value */
> +	fb_write(0, fbi->dss, O4_DSS_CTRL);
> +
> +	return 0;
> +}
> +
> +static struct fb_ops omap4fb_ops = {
> +	.fb_enable		= omap4fb_enable,
> +	.fb_disable		= omap4fb_disable,
> +	.fb_activate_var	= omap4fb_activate_var,
> +};
> +
> +static int omap4fb_probe(struct device_d *dev)
> +{
> +	struct omap4fb_platform_data const *pdata = dev->platform_data;
> +	struct omap4fb_device *fbi;
> +	struct fb_info *info;
> +	int rc;
> +	size_t i;
> +
> +	if (!pdata)
> +		return -ENODEV;
> +
> +	fbi = xzalloc(sizeof *fbi +
> +		      pdata->num_displays * sizeof fbi->video_modes[0]);
> +	info = &fbi->info;
> +
> +	fbi->dev = dev;
> +
> +	/* CM_DSS_CLKSTCTRL (TRM: 935) trigger SW_WKUP */
> +	__raw_writel(0x2, 0x4a009100); /* TODO: move this to clockmanagement */
> +
> +	fbi->dss   = dev_request_mem_region_by_name(dev, "omap4_dss");
> +	fbi->dispc = dev_request_mem_region_by_name(dev, "omap4_dispc");
> +
> +	if (!fbi->dss || !fbi->dispc) {
> +		dev_err(dev, "Insufficient register description\n");
> +		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	dev_info(dev, "HW-Revision 0x%04x 0x%04x\n",
> +		fb_read(fbi->dss, O4_DISPC_REVISION),
> +		fb_read(fbi->dss, O4_DSS_REVISION));
> +
> +
drop one line
> +	if (!pdata->dss_clk_hz | !pdata->displays | !pdata->num_displays |
> +		!pdata->bpp) {
> +		dev_err(dev, "Insufficient omap4fb_platform_data\n");
> +		rc = -EINVAL;
> +		goto out;
> +	}
> +
> +	fbi->enable_fn    = pdata->enable;
> +	fbi->displays     = pdata->displays;
> +	fbi->num_displays = pdata->num_displays;
> +	fbi->divisor.dss_clk_hz = pdata->dss_clk_hz;
> +
> +	for (i = 0; i < pdata->num_displays; ++i)
> +		fbi->video_modes[i] = pdata->displays[i].mode;
> +
> +	info->mode_list = fbi->video_modes;
> +	info->num_modes = pdata->num_displays;
> +
> +	info->priv = fbi;
> +	info->fbops = &omap4fb_ops;
> +	info->bits_per_pixel = pdata->bpp;
> +
> +	if (pdata->screen) {
> +		if (!IS_ALIGNED(pdata->screen->start, PAGE_SIZE) ||
> +		    !IS_ALIGNED(resource_size(pdata->screen), PAGE_SIZE)) {
> +			dev_err(dev, "screen resource not aligned\n");
> +			rc = -EINVAL;
> +			goto out;
> +		}
> +		fbi->prealloc_screen.addr =
> +				(void __iomem *)pdata->screen->start;
> +		fbi->prealloc_screen.size = resource_size(pdata->screen);
> +		remap_range(fbi->prealloc_screen.addr,
> +			fbi->prealloc_screen.size,
> +			mmu_get_pte_uncached_flags());
> +	}
> +
> +	rc = omap4fb_reset(fbi);
> +	if (rc < 0) {
> +		dev_err(dev, "failed to reset: %d\n", rc);
> +		goto out;
> +	}
> +
> +	rc = register_framebuffer(info);
> +	if (rc < 0) {
> +		dev_err(dev, "failed to register framebuffer: %d\n", rc);
> +		goto out;
> +	}
> +
> +	rc = 0;
> +	dev_info(dev, "registered\n");
> +
> +out:
> +	if (rc < 0)
> +		free(fbi);
> +
> +	return rc;
> +}
> +
> +static struct driver_d omap4fb_driver = {
> +	.name	= "omap4_fb",
> +	.probe	= omap4fb_probe,
> +};
> +
> +static int omap4fb_init(void)
> +{
> +	return platform_driver_register(&omap4fb_driver);
> +}
> +
> +device_initcall(omap4fb_init);
> diff --git a/drivers/video/omap4.h b/drivers/video/omap4.h
> new file mode 100644
> index 0000000..5704f7b
> --- /dev/null
> +++ b/drivers/video/omap4.h
> @@ -0,0 +1,181 @@
> +/*
> + * TI Omap4 Frame Buffer device driver
> + *
> + * Copyright (C) 2013 Christoph Fritz <chf.fritz at googlemail.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef H_BAREBOX_DRIVER_VIDEO_OMAP4_REGS_H
> +#define H_BAREBOX_DRIVER_VIDEO_OMAP4_REGS_H
> +
> +#include <types.h>
> +#include <common.h>
> +
> +#define O4_TIMEOUT	(128 * USECOND)
> +
> +#define fb_read(io, reg)		__raw_readl((io)+(reg))
> +#define fb_write(val, io, reg)	__raw_writel((val), (io)+(reg))
fb_read is too much generic

better to use 2 macro for both resources and pass the fbi struct
> +
> +/* TRM: 10.1.3.2 DSS Registers */
> +#define O4_DSS_REVISION	0x0
> +#define O4_DSS_SYSSTATUS	0x14
> +#define O4_DSS_CTRL		0x40
> +#define O4_DSS_STATUS		0x5c
> +
> +/* TRM: 10.2.7.3 Display Controller Registers */
> +#define O4_DISPC_REVISION		0x0
> +#define O4_DISPC_IRQSTATUS		0x18
> +#define O4_DISPC_CONTROL2		0x238
> +#define O4_DISPC_VID1_ATTRIBUTES	0xcc
> +#define O4_DISPC_TIMING_H2		0x400
> +#define O4_DISPC_TIMING_V2		0x404
> +#define O4_DISPC_POL_FREQ2		0x408
> +#define O4_DISPC_DIVISOR2		0x40c
> +#define O4_DISPC_DEFAULT_COLOR2	0x3ac
> +#define O4_DISPC_SIZE_LCD2		0x3cc
> +#define O4_DISPC_DIVISOR		0x804
> +#define O4_DISPC_VID1_BA0		0xbc
> +#define O4_DISPC_VID1_BA1		0xc0
> +#define O4_DISPC_VID1_POSITION		0xc4
> +#define O4_DISPC_VID1_SIZE		0xc8
> +#define O4_DISPC_VID1_PICTURE_SIZE	0xe4
> +#define O4_DISPC_VID1_ROW_INC		0xd8
> +#define O4_DISPC_VID1_PIXEL_INC	0xdc
> +#define O4_DISPC_VID1_PRELOAD		0x230
> +
> +#define DSS_DISPC_VIDn_POSITION_VIDPOSX(_x)		((_x) << 0)
> +#define DSS_DISPC_VIDn_POSITION_VIDPOSY(_y)		((_y) << 16)
> +
> +#define DSS_DISPC_VIDn_PICTURE_SIZE_VIDORGSIZEX(_x)	((_x) << 0)
> +#define DSS_DISPC_VIDn_PICTURE_SIZE_VIDORGSIZEY(_y)	((_y) << 16)
> +
> +#define DSS_DISPC_VIDn_SIZE_VIDSIZEX(_x)		((_x) << 0)
> +#define DSS_DISPC_VIDn_SIZE_VIDSIZEY(_y)		((_y) << 16)
> +
> +#define DSS_DISPC_SIZE_LCD_PPL(_x)			((_x) << 0)
> +#define DSS_DISPC_SIZE_LCD_LPP(_y)			((_y) << 16)
> +
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDENABLE		(1u << 0)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(_fmt)	((_fmt) << 1)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_RGB12	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(4u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_ARGB16	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(5u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_RGB16	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(6u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_ARGB16o	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(7u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_xRGB24u	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(8u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_RGB24p	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(9u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_YUV2	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(10u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_UYVY	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(11u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_ARGB32	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(12u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_RGBA32	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(13u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT_xRGB32	\
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDFORMAT(14u)
> +
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE(_b)	((_b) << 14)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE_2x128 \
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE(0u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE_4x128 \
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE(1u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE_8x128 \
> +	DSS_DISPC_VIDn_ATTRIBUTES_VIDBURSTSIZE(2u)
> +
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDCHANNELOUT	(1u << 16)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_SELFREFRESHAUTO	(1u << 17)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDFIFOPRELOAD	(1u << 19)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDVERTICALTAPS	(1u << 21)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_DOUBLESTRIDE		(1u << 22)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDARBITRATION	(1u << 23)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_VIDSELFREFRESH	(1u << 24)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_ZORDERENABLE		(1u << 25)
> +
> +#define DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2(_b)  ((_b) << 30)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2_PRIMARY_LCD \
> +	DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2(0u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2_SECONDARY_LCD \
> +	DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2(1u)
> +#define DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2_WRITEBACK_MEM \
> +	DSS_DISPC_VIDn_ATTRIBUTES_CHANNELOUT2(3u)
> +
> +#define DSS_DISPC_CONTROL_LCDENABLE			(1u << 0)
> +#define DSS_DISPC_CONTROL_TVENABLE			(1u << 1)
> +#define DSS_DISPC_CONTROL_MONOCOLOR			(1u << 2)
> +#define DSS_DISPC_CONTROL_STNTFT			(1u << 3)
> +#define DSS_DISPC_CONTROL_M8B				(1u << 4)
> +#define DSS_DISPC_CONTROL_GOLCD			(1u << 5)
> +#define DSS_DISPC_CONTROL_GOTV				(1u << 6)
> +#define DSS_DISPC_CONTROL_STDITHERENABLE		(1u << 7)
> +
> +#define DSS_DISPC_CONTROL_TFTDATALINES(_l)		((_l) << 8)
> +#define DSS_DISPC_CONTROL_TFTDATALINES_12 \
> +	DSS_DISPC_CONTROL_TFTDATALINES(0u)
> +#define DSS_DISPC_CONTROL_TFTDATALINES_16 \
> +	DSS_DISPC_CONTROL_TFTDATALINES(1u)
> +#define DSS_DISPC_CONTROL_TFTDATALINES_18 \
> +	DSS_DISPC_CONTROL_TFTDATALINES(2u)
> +#define DSS_DISPC_CONTROL_TFTDATALINES_24 \
> +	DSS_DISPC_CONTROL_TFTDATALINES(3u)
> +
> +#define DSS_DISPC_CONTROL_STALLMODE			(1u << 11)
> +#define DSS_DISPC_CONTROL_OVERLAYOPTIMIZATION		(1u << 12)
> +#define DSS_DISPC_CONTROL_GPIN0			(1u << 13) /* ro */
> +#define DSS_DISPC_CONTROL_GPIN1			(1u << 14) /* ro */
> +#define DSS_DISPC_CONTROL_GPOUT0			(1u << 15)
> +#define DSS_DISPC_CONTROL_GPOUT1			(1u << 16)
> +#define DSS_DISPC_CONTROL_HT(_ht)			((_ht) << 17)
> +#define DSS_DISPC_CONTROL_TDMENABLE			(1u << 20)
> +#define DSS_DISPC_CONTROL_TDMPARALLELMODE(_pm)		((_pm) << 21)
> +#define DSS_DISPC_CONTROL_TDMCYCLEFORMAT(_cf)		((_cf) << 23)
> +#define DSS_DISPC_CONTROL_TDMUNUSEDBITS(_ub)		((_ub) << 25)
> +#define DSS_DISPC_CONTROL_PCKFREEENABLE		(1u << 27)
> +#define DSS_DISPC_CONTROL_LCDENABLESIGNAL		(1u << 28)
> +#define DSS_DISPC_CONTROL_LCDENABLEPOL			(1u << 29)
> +#define DSS_DISPC_CONTROL_SPATIALTEMPD(_df)		((_df) << 30)
> +
> +#define DSS_DISPC_POL_FREQ_IVS				(1u << 12)
> +#define DSS_DISPC_POL_FREQ_IHS				(1u << 13)
> +#define DSS_DISPC_POL_FREQ_IPC				(1u << 14)
> +#define DSS_DISPC_POL_FREQ_IEO				(1u << 15)
> +#define DSS_DISPC_POL_FREQ_RF				(1u << 16)
> +#define DSS_DISPC_POL_FREQ_ONOFF			(1u << 17)
> +
> +#define DSS_DISPC_TIMING_H_HSW(_hsw)			((_hsw) << 0)
> +#define DSS_DISPC_TIMING_H_HFP(_hfp)			((_hfp) << 8)
> +#define DSS_DISPC_TIMING_H_HBP(_hbp)			((_hbp) << 20)
> +
> +#define DSS_DISPC_TIMING_V_VSW(_vsw)			((_vsw) << 0)
> +#define DSS_DISPC_TIMING_V_VFP(_vfp)			((_vfp) << 8)
> +#define DSS_DISPC_TIMING_V_VBP(_vbp)			((_vbp) << 20)
> +
> +#define DSS_DISPC_DIVISOR_ENABLE			(1u << 0)
> +#define DSS_DISPC_DIVISOR_LCD(_lcd)			((_lcd) << 16)
> +
> +#define DSS_DISPC_DIVISOR2_PCD(_pcd)			((_pcd) << 0)
> +#define DSS_DISPC_DIVISOR2_LCD(_lcd)			((_lcd) << 16)
> +
> +#define DSS_DISPC_IRQSTATUS_FRAMEDONE			(1u << 0)
> +#define DSS_DISPC_IRQSTATUS_FRAMEDONE2			(1u << 22)
> +
> +#define DSS_DSS_SYSSTATUS_RESETDONE			(1u << 0)
> +
> +#endif	/* H_BAREBOX_DRIVER_VIDEO_O4_REGS_H */
> -- 
> 1.7.10.4
> 
> 
> 



More information about the barebox mailing list