/*
* Freescale i.MX Frame Buffer device driver
*
* Copyright (C) 2004 Sascha Hauer, Pengutronix
* Based on acornfb.c Copyright (C) Russell King.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
* Please direct your questions and comments on this driver to the following
* email address:
*
* linux-arm-kernel@lists.arm.linux.org.uk
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/cpufreq.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
#include <linux/platform_data/video-imxfb.h>
/*
* Complain if VAR is out of range.
*/
#define DEBUG_VAR 1
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
(defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) && \
defined(CONFIG_FB_IMX_MODULE))
#define PWMR_BACKLIGHT_AVAILABLE
#endif
#define DRIVER_NAME "imx-fb"
#define LCDC_SSA 0x00
#define LCDC_SIZE 0x04
#define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
#define YMAX_MASK_IMX1 0x1ff
#define YMAX_MASK_IMX21 0x3ff
#define LCDC_VPW 0x08
#define VPW_VPW(x) ((x) & 0x3ff)
#define LCDC_CPOS 0x0C
#define CPOS_CC1 (1<<31)
#define CPOS_CC0 (1<<30)
#define CPOS_OP (1<<28)
#define CPOS_CXP(x) (((x) & 3ff) << 16)
#define LCDC_LCWHB 0x10
#define LCWHB_BK_EN (1<<31)
#define LCWHB_CW(w) (((w) & 0x1f) << 24)
#define LCWHB_CH(h) (((h) & 0x1f) << 16)
#define LCWHB_BD(x) ((x) & 0xff)
#define LCDC_LCHCC 0x14
#define LCDC_PCR 0x18
#define LCDC_HCR 0x1C
#define HCR_H_WIDTH(x) (((x) & 0x3f) << 26)
#define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
#define HCR_H_WAIT_2(x) ((x) & 0xff)
#define LCDC_VCR 0x20
#define VCR_V_WIDTH(x) (((x) & 0x3f) << 26)
#define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
#define VCR_V_WAIT_2(x) ((x) & 0xff)
#define LCDC_POS 0x24
#define POS_POS(x) ((x) & 1f)
#define LCDC_LSCR1 0x28
/* bit fields in imxfb.h */
#define LCDC_PWMR 0x2C
/* bit fields in imxfb.h */
#define LCDC_DMACR 0x30
/* bit fields in imxfb.h */
#define LCDC_RMCR 0x34
#define RMCR_LCDC_EN_MX1 (1<<1)
#define RMCR_SELF_REF (1<<0)
#define LCDC_LCDICR 0x38
#define LCDICR_INT_SYN (1<<2)
#define LCDICR_INT_CON (1)
#define LCDC_LCDISR 0x40
#define LCDISR_UDR_ERR (1<<3)
#define LCDISR_ERR_RES (1<<2)
#define LCDISR_EOF (1<<1)
#define LCDISR_BOF (1<<0)
#define IMXFB_LSCR1_DEFAULT 0x00120300
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
/*
* These are the bitfields for each
* display depth that we support.
*/
struct imxfb_rgb {
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
};
enum imxfb_type {
IMX1_FB,
IMX21_FB,
};
struct imxfb_info {
struct platform_device *pdev;
void __iomem *regs;
struct clk *clk_ipg;
struct clk *clk_ahb;
struct clk *clk_per;
enum imxfb_type devtype;
bool enabled;
/*
* These are the addresses we mapped
* the framebuffer memory region to.
*/
dma_addr_t map_dma;
u_char *map_cpu;
u_int map_size;
u_char *screen_cpu;
dma_addr_t screen_dma;
u_int palette_size;
dma_addr_t dbar1;
dma_addr_t dbar2;
u_int pcr;
u_int pwmr;
u_int lscr1;
u_int dmacr;
u_int cmap_inverse:1,
cmap_static:1,
unused:30;
struct imx_fb_videomode *mode;
int num_modes;
#ifdef PWMR_BACKLIGHT_AVAILABLE
struct backlight_device *bl;
#endif
void (*lcd_power)(int);
void (*backlight_power)(int);
};
static struct platform_device_id imxfb_devtype[] = {
{
.name = "imx1-fb",
.driver_data = IMX1_FB,
}, {
.name = "imx21-fb",
.driver_data = IMX21_FB,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, imxfb_devtype);
static struct of_device_id imxfb_of_dev_id[] = {
{
.compatible = "fsl,imx1-fb",
.data = &imxfb_devtype[IMX1_FB],
}, {
.compatible = "fsl,imx21-fb",
.data = &imxfb_devtype[IMX21_FB],
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, imxfb_of_dev_id);
static inline int is_imx1_fb(struct imxfb_info *fbi)
{
return fbi->devtype == IMX1_FB;
}
#define IMX_NAME "IMX"
/*