diff options
author | Robby Cai <R63905@freescale.com> | 2010-01-27 21:57:21 +0800 |
---|---|---|
committer | Alejandro Gonzalez <alex.gonzalez@digi.com> | 2010-05-25 11:13:35 +0200 |
commit | 93d8cc863026587589dd6bc97f5b49340a048d3f (patch) | |
tree | b32f4935e5df93e9179cdb88441df02e9e633fa1 /drivers/video | |
parent | c24986360fa6ca2e5ce49b78191e14549b29d4af (diff) |
ENGR00117728-2 MX28 Add lcdif and framebuffer driver support
add lcdif, fb, lcd controller(43wvf1g) driver
Signed-off-by: Robby Cai <R63905@freescale.com>
Signed-off-by: Alejandro Gonzalez <alex.gonzalez@digi.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 4 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/mxs/Kconfig | 15 | ||||
-rw-r--r-- | drivers/video/mxs/Makefile | 3 | ||||
-rw-r--r-- | drivers/video/mxs/lcd_43wvf1g.c | 289 | ||||
-rw-r--r-- | drivers/video/mxs/lcdif.c | 224 | ||||
-rw-r--r-- | drivers/video/mxs/mxsfb.c | 485 |
7 files changed, 622 insertions, 399 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 53de81d71ed2..1b3bd4429adc 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -385,6 +385,10 @@ if ARCH_MXC source "drivers/video/mxc/Kconfig" endif +if ARCH_MXS +source "drivers/video/mxs/Kconfig" +endif + config FB_SA1100 bool "SA-1100 LCD support" depends on (FB = y) && ARM && ARCH_SA1100 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e56f7b139957..d3d951e0c4eb 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_MXC) += mxc/ +obj-$(CONFIG_FB_MXS) += mxs/ obj-$(CONFIG_FB_STMP37XX) += stmp37xxfb.o obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o diff --git a/drivers/video/mxs/Kconfig b/drivers/video/mxs/Kconfig new file mode 100644 index 000000000000..fa0dd1e2718e --- /dev/null +++ b/drivers/video/mxs/Kconfig @@ -0,0 +1,15 @@ +config FB_MXS + tristate "MXS Framebuffer driver" + depends on FB && ARCH_MX28 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + ---help--- + Say Y here to enable support for the framebuffer driver for the + Freescale MXS Board. + +config FB_MXS_LCD_43WVF1G + depends on FB_MXS + tristate "SEIKO 4.3' LCD WVGA(800x480) PANEL" + default y diff --git a/drivers/video/mxs/Makefile b/drivers/video/mxs/Makefile new file mode 100644 index 000000000000..892b04f0d7cc --- /dev/null +++ b/drivers/video/mxs/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_ARCH_MXS) += lcdif.o +obj-$(CONFIG_FB_MXS) += mxsfb.o +obj-$(CONFIG_FB_MXS_LCD_43WVF1G) += lcd_43wvf1g.o diff --git a/drivers/video/mxs/lcd_43wvf1g.c b/drivers/video/mxs/lcd_43wvf1g.c new file mode 100644 index 000000000000..1a8157f277a0 --- /dev/null +++ b/drivers/video/mxs/lcd_43wvf1g.c @@ -0,0 +1,289 @@ +/* + * Freescale MX28 Seiko 43WVF1G LCD panel driver + * + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/notifier.h> +#include <linux/regulator/consumer.h> +#include <linux/platform_device.h> + +#include <mach/device.h> +#include <mach/lcdif.h> +#include <mach/regs-pwm.h> +#include <mach/system.h> + +#define DOTCLK_H_ACTIVE 800 +#define DOTCLK_H_PULSE_WIDTH 10 +#define DOTCLK_HF_PORCH 164 +#define DOTCLK_HB_PORCH 89 +#define DOTCLK_H_WAIT_CNT (DOTCLK_H_PULSE_WIDTH + DOTCLK_HB_PORCH) +#define DOTCLK_H_PERIOD (DOTCLK_H_WAIT_CNT + DOTCLK_HF_PORCH + DOTCLK_H_ACTIVE) + +#define DOTCLK_V_ACTIVE 480 +#define DOTCLK_V_PULSE_WIDTH 10 +#define DOTCLK_VF_PORCH 10 +#define DOTCLK_VB_PORCH 23 +#define DOTCLK_V_WAIT_CNT (DOTCLK_V_PULSE_WIDTH + DOTCLK_VB_PORCH) +#define DOTCLK_V_PERIOD (DOTCLK_VF_PORCH + DOTCLK_V_ACTIVE + DOTCLK_V_WAIT_CNT) + +static struct mxs_platform_bl_data bl_data; +static struct clk *lcd_clk; + +static int init_panel(struct device *dev, dma_addr_t phys, int memsize, + struct mxs_platform_fb_entry *pentry) +{ + int ret = 0; + lcd_clk = clk_get(dev, "dis_lcdif"); + if (IS_ERR(lcd_clk)) { + ret = PTR_ERR(lcd_clk); + goto out; + } + ret = clk_enable(lcd_clk); + if (ret) { + clk_put(lcd_clk); + goto out; + } + + ret = clk_set_rate(lcd_clk, 1000000 / pentry->cycle_time_ns); /* kHz */ + if (ret) { + clk_disable(lcd_clk); + clk_put(lcd_clk); + goto out; + } + + /* + * Make sure we do a high-to-low transition to reset the panel. + * First make it low for 100 msec, hi for 10 msec, low for 10 msec, + * then hi. + */ + __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); /* low */ + mdelay(100); + __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); /* high */ + mdelay(10); + __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); /* low */ + + /* For the Samsung, Reset must be held low at least 30 uSec + * Therefore, we'll hold it low for about 10 mSec just to be sure. + * Then we'll wait 1 mSec afterwards. + */ + mdelay(10); + __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); /* high */ + mdelay(1); + + setup_dotclk_panel(DOTCLK_V_PULSE_WIDTH, DOTCLK_V_PERIOD, + DOTCLK_V_WAIT_CNT, DOTCLK_V_ACTIVE, + DOTCLK_H_PULSE_WIDTH, DOTCLK_H_PERIOD, + DOTCLK_H_WAIT_CNT, DOTCLK_H_ACTIVE, 0); + + ret = mxs_lcdif_dma_init(dev, phys, memsize); + if (ret) + goto out; + + mxs_lcd_set_bl_pdata(pentry->bl_data); + mxs_lcdif_notify_clients(MXS_LCDIF_PANEL_INIT, pentry); + return 0; + +out: + return ret; +} + +static void release_panel(struct device *dev, + struct mxs_platform_fb_entry *pentry) +{ + mxs_lcdif_notify_clients(MXS_LCDIF_PANEL_RELEASE, pentry); + release_dotclk_panel(); + mxs_lcdif_dma_release(); + clk_disable(lcd_clk); + clk_put(lcd_clk); +} + +static int blank_panel(int blank) +{ + int ret = 0, count; + + switch (blank) { + case FB_BLANK_NORMAL: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + for (count = 10000; count; count--) { + if (__raw_readl(REGS_LCDIF_BASE + HW_LCDIF_STAT) & + BM_LCDIF_STAT_TXFIFO_EMPTY) + break; + udelay(1); + } + break; + + case FB_BLANK_UNBLANK: + __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + break; + + default: + ret = -EINVAL; + } + return ret; +} + +static struct mxs_platform_fb_entry fb_entry = { + .name = "43wvf1g", + .x_res = 480, + .y_res = 800, + .bpp = 32, + .cycle_time_ns = 30, + .lcd_type = MXS_LCD_PANEL_DOTCLK, + .init_panel = init_panel, + .release_panel = release_panel, + .blank_panel = blank_panel, + .run_panel = mxs_lcdif_run, + .stop_panel = mxs_lcdif_stop, + .pan_display = mxs_lcdif_pan_display, + .bl_data = &bl_data, +}; + +static struct clk *pwm_clk; + +static int init_bl(struct mxs_platform_bl_data *data) +{ + int ret = 0; + + pwm_clk = clk_get(NULL, "pwm"); + if (IS_ERR(pwm_clk)) { + ret = PTR_ERR(pwm_clk); + return ret; + } + clk_enable(pwm_clk); + mxs_reset_block(REGS_PWM_BASE, 1); + + __raw_writel(BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0), + REGS_PWM_BASE + HW_PWM_ACTIVEn(2)); + __raw_writel(BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599), + REGS_PWM_BASE + HW_PWM_PERIODn(2)); + __raw_writel(BM_PWM_CTRL_PWM2_ENABLE, REGS_PWM_BASE + HW_PWM_CTRL_SET); + + return 0; +} + +static void free_bl(struct mxs_platform_bl_data *data) +{ + __raw_writel(BF_PWM_ACTIVEn_INACTIVE(0) | + BF_PWM_ACTIVEn_ACTIVE(0), + REGS_PWM_BASE + HW_PWM_ACTIVEn(2)); + __raw_writel(BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(599), + REGS_PWM_BASE + HW_PWM_PERIODn(2)); + __raw_writel(BM_PWM_CTRL_PWM2_ENABLE, REGS_PWM_BASE + HW_PWM_CTRL_CLR); + + clk_disable(pwm_clk); + clk_put(pwm_clk); +} + +static int values[] = { 0, 4, 9, 14, 20, 27, 35, 45, 57, 75, 100 }; + +static int power[] = { + 0, 1500, 3600, 6100, 10300, + 15500, 74200, 114200, 155200, + 190100, 191000 +}; + +static int bl_to_power(int br) +{ + int base; + int rem; + + if (br > 100) + br = 100; + base = power[br / 10]; + rem = br % 10; + if (!rem) + return base; + else + return base + (rem * (power[br / 10 + 1]) - base) / 10; +} + +static int set_bl_intensity(struct mxs_platform_bl_data *data, + struct backlight_device *bd, int suspended) +{ + int intensity = bd->props.brightness; + int scaled_int; + + if (bd->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bd->props.fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + if (suspended) + intensity = 0; + + /* + * This is not too cool but what can we do? + * Luminance changes non-linearly... + */ + if (regulator_set_current_limit + (data->regulator, bl_to_power(intensity), bl_to_power(intensity))) + return -EBUSY; + + scaled_int = values[intensity / 10]; + if (scaled_int < 100) { + int rem = intensity - 10 * (intensity / 10); /* r = i % 10; */ + scaled_int += rem * (values[intensity / 10 + 1] - + values[intensity / 10]) / 10; + } + __raw_writel(BF_PWM_ACTIVEn_INACTIVE(scaled_int) | + BF_PWM_ACTIVEn_ACTIVE(0), + REGS_PWM_BASE + HW_PWM_ACTIVEn(2)); + __raw_writel(BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ + BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ + BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ + BF_PWM_PERIODn_PERIOD(399), + REGS_PWM_BASE + HW_PWM_PERIODn(2)); + return 0; +} + +static struct mxs_platform_bl_data bl_data = { + .bl_max_intensity = 100, + .bl_default_intensity = 50, + .bl_cons_intensity = 50, + .init_bl = init_bl, + .free_bl = free_bl, + .set_bl_intensity = set_bl_intensity, +}; + +static int __init register_devices(void) +{ + struct platform_device *pdev; + pdev = mxs_get_device("mxs-fb", 0); + if (pdev == NULL || IS_ERR(pdev)) + return -ENODEV; + + mxs_lcd_register_entry(&fb_entry, pdev->dev.platform_data); + + return 0; +} + +subsys_initcall(register_devices); diff --git a/drivers/video/mxs/lcdif.c b/drivers/video/mxs/lcdif.c index 5cdd52a0f10b..fc95e3d616d7 100644 --- a/drivers/video/mxs/lcdif.c +++ b/drivers/video/mxs/lcdif.c @@ -1,210 +1,138 @@ /* - * Freescale STMP378X LCDIF low-level routines + * Freescale MXS LCDIF low-level routines * * Author: Vitaly Wool <vital@embeddedalley.com> * - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* #define DEBUG */ -#include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <mach/hardware.h> -#include <mach/dma.h> -#include <mach/dma.h> -#include <mach/regs-lcdif.h> -#include <mach/regs-pinctrl.h> #include <mach/lcdif.h> +#include <mach/regs-lcdif.h> -#define MAX_CHAIN_LEN 10 - -static struct stmp3xxx_dma_descriptor video_dma_descriptor[MAX_CHAIN_LEN]; -static struct stmp3xxx_lcd_dma_chain_info dma_chain_info[MAX_CHAIN_LEN]; -static unsigned dma_chain_info_pos; +#define REGS_LCDIF_BASE IO_ADDRESS(LCDIF_PHYS_ADDR) -void stmp3xxx_init_lcdif(void) +void mxs_init_lcdif(void) { - stmp3xxx_clearl(BM_LCDIF_CTRL_CLKGATE, REGS_LCDIF_BASE + HW_LCDIF_CTRL); + __raw_writel(BM_LCDIF_CTRL_CLKGATE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); /* Reset controller */ - stmp3xxx_setl(BM_LCDIF_CTRL_SFTRST, REGS_LCDIF_BASE + HW_LCDIF_CTRL); + __raw_writel(BM_LCDIF_CTRL_SFTRST, REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); udelay(10); /* Take controller out of reset */ - stmp3xxx_clearl(BM_LCDIF_CTRL_SFTRST | BM_LCDIF_CTRL_CLKGATE, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); + __raw_writel(BM_LCDIF_CTRL_SFTRST | BM_LCDIF_CTRL_CLKGATE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); /* Setup the bus protocol */ - stmp3xxx_clearl(BM_LCDIF_CTRL1_MODE86, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1); - stmp3xxx_clearl(BM_LCDIF_CTRL1_BUSY_ENABLE, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1); + __raw_writel(BM_LCDIF_CTRL1_MODE86, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + __raw_writel(BM_LCDIF_CTRL1_BUSY_ENABLE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); /* Take display out of reset */ - stmp3xxx_setl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); + __raw_writel(BM_LCDIF_CTRL1_RESET, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); /* VSYNC is an input by default */ - stmp3xxx_setl(BM_LCDIF_VDCTRL0_VSYNC_OEB, - REGS_LCDIF_BASE + HW_LCDIF_VDCTRL0); + __raw_writel(BM_LCDIF_VDCTRL0_VSYNC_OEB, + REGS_LCDIF_BASE + HW_LCDIF_VDCTRL0_SET); /* Reset display */ - stmp3xxx_clearl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); + __raw_writel(BM_LCDIF_CTRL1_RESET, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); udelay(10); - stmp3xxx_setl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); + __raw_writel(BM_LCDIF_CTRL1_RESET, + REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); udelay(10); } +EXPORT_SYMBOL(mxs_init_lcdif); -EXPORT_SYMBOL(stmp3xxx_init_lcdif); - -static int stmp378x_lcd_master = 1; -int stmp3xxx_lcdif_dma_init(struct device *dev, dma_addr_t phys, int memsize, - int lcd_master) +int mxs_lcdif_dma_init(struct device *dev, dma_addr_t phys, int memsize) { - int ret = 0; - - stmp378x_lcd_master = lcd_master; - if (lcd_master) { - stmp3xxx_setl(BM_LCDIF_CTRL_LCDIF_MASTER, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); - - __raw_writel(phys, REGS_LCDIF_BASE + HW_LCDIF_CUR_BUF); - __raw_writel(phys, REGS_LCDIF_BASE + HW_LCDIF_NEXT_BUF); - } else { - ret = - stmp3xxx_dma_request(STMP3XXX_DMA - (LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), - dev, "lcdif"); - if (ret) { - dev_err(dev, - "stmp3xxx_dma_request failed: error %d\n", ret); - goto out; - } - - stmp3xxx_dma_reset_channel(STMP3XXX_DMA - (LCD_DMA_CHANNEL, - STMP3XXX_BUS_APBH)); - - stmp3xxx_dma_clear_interrupt(STMP3XXX_DMA - (LCD_DMA_CHANNEL, - STMP3XXX_BUS_APBH)); - stmp3xxx_dma_enable_interrupt(STMP3XXX_DMA - (LCD_DMA_CHANNEL, - STMP3XXX_BUS_APBH)); - - dotclk_dma_chain_init(memsize, phys, video_dma_descriptor, - dma_chain_info, &dma_chain_info_pos); - } -out: - return ret; -} + __raw_writel(BM_LCDIF_CTRL_LCDIF_MASTER, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); -EXPORT_SYMBOL(stmp3xxx_lcdif_dma_init); + __raw_writel(phys, REGS_LCDIF_BASE + HW_LCDIF_CUR_BUF); + __raw_writel(phys, REGS_LCDIF_BASE + HW_LCDIF_NEXT_BUF); -void stmp3xxx_lcdif_dma_release(void) -{ - int i; - - if (stmp378x_lcd_master) { - stmp3xxx_clearl(BM_LCDIF_CTRL_LCDIF_MASTER, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); - return; - } - - for (i = 0; i < dma_chain_info_pos; i++) - stmp3xxx_dma_free_command(STMP3XXX_DMA - (LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), - &video_dma_descriptor[i]); - stmp3xxx_dma_release(STMP3XXX_DMA(LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH)); - - dma_chain_info_pos = 0; + return 0; } +EXPORT_SYMBOL(mxs_lcdif_dma_init); -EXPORT_SYMBOL(stmp3xxx_lcdif_dma_release); - -void stmp3xxx_lcdif_run(void) +void mxs_lcdif_dma_release(void) { - if (stmp378x_lcd_master) { - stmp3xxx_setl(BM_LCDIF_CTRL_LCDIF_MASTER, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); - stmp3xxx_setl(BM_LCDIF_CTRL_RUN, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); - } else { - video_dma_descriptor[dma_chain_info_pos - 1].command->cmd &= - ~BM_APBH_CHn_CMD_SEMAPHORE; - stmp3xxx_dma_go(STMP3XXX_DMA - (LCD_DMA_CHANNEL, STMP3XXX_BUS_APBH), - video_dma_descriptor, 1); - } + __raw_writel(BM_LCDIF_CTRL_LCDIF_MASTER, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + return; } +EXPORT_SYMBOL(mxs_lcdif_dma_release); -EXPORT_SYMBOL(stmp3xxx_lcdif_run); - -void stmp3xxx_lcdif_stop(void) +void mxs_lcdif_run(void) { - if (stmp378x_lcd_master) { - stmp3xxx_clearl(BM_LCDIF_CTRL_RUN, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); - stmp3xxx_clearl(BM_LCDIF_CTRL_LCDIF_MASTER, - REGS_LCDIF_BASE + HW_LCDIF_CTRL); - udelay(100); - } else { - video_dma_descriptor[dma_chain_info_pos - 1].command->cmd |= - BM_APBH_CHn_CMD_SEMAPHORE; - udelay(100); - } - stmp3xxx_setl(BM_LCDIF_CTRL_CLKGATE, REGS_LCDIF_BASE + HW_LCDIF_CTRL); + __raw_writel(BM_LCDIF_CTRL_LCDIF_MASTER, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); + __raw_writel(BM_LCDIF_CTRL_RUN, REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); } +EXPORT_SYMBOL(mxs_lcdif_run); -EXPORT_SYMBOL(stmp3xxx_lcdif_stop); +void mxs_lcdif_stop(void) +{ + __raw_writel(BM_LCDIF_CTRL_RUN, REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + __raw_writel(BM_LCDIF_CTRL_LCDIF_MASTER, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR); + udelay(100); + + __raw_writel(BM_LCDIF_CTRL_CLKGATE, + REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET); +} +EXPORT_SYMBOL(mxs_lcdif_stop); -int stmp3xxx_lcdif_pan_display(dma_addr_t addr) +int mxs_lcdif_pan_display(dma_addr_t addr) { - if (stmp378x_lcd_master) - __raw_writel(addr, REGS_LCDIF_BASE + HW_LCDIF_NEXT_BUF); - else { - int i; - /* Modify the chain addresses */ - for (i = 0; i < dma_chain_info_pos; ++i) { - *dma_chain_info[i].dma_addr_p = addr + - dma_chain_info[i].offset; - barrier(); - } - } + __raw_writel(addr, REGS_LCDIF_BASE + HW_LCDIF_NEXT_BUF); + return 0; } -EXPORT_SYMBOL(stmp3xxx_lcdif_pan_display); +EXPORT_SYMBOL(mxs_lcdif_pan_display); static BLOCKING_NOTIFIER_HEAD(lcdif_client_list); -int stmp3xxx_lcdif_register_client(struct notifier_block *nb) +int mxs_lcdif_register_client(struct notifier_block *nb) { return blocking_notifier_chain_register(&lcdif_client_list, nb); } -EXPORT_SYMBOL(stmp3xxx_lcdif_register_client); +EXPORT_SYMBOL(mxs_lcdif_register_client); -void stmp3xxx_lcdif_unregister_client(struct notifier_block *nb) +void mxs_lcdif_unregister_client(struct notifier_block *nb) { blocking_notifier_chain_unregister(&lcdif_client_list, nb); } +EXPORT_SYMBOL(mxs_lcdif_unregister_client); -EXPORT_SYMBOL(stmp3xxx_lcdif_unregister_client); - -void stmp3xxx_lcdif_notify_clients(unsigned long event, - struct stmp3xxx_platform_fb_entry *pentry) +void mxs_lcdif_notify_clients(unsigned long event, + struct mxs_platform_fb_entry *pentry) { blocking_notifier_call_chain(&lcdif_client_list, event, pentry); } - -EXPORT_SYMBOL(stmp3xxx_lcdif_notify_clients); +EXPORT_SYMBOL(mxs_lcdif_notify_clients); diff --git a/drivers/video/mxs/mxsfb.c b/drivers/video/mxs/mxsfb.c index 9ecbde89b735..a7eca468ac3e 100644 --- a/drivers/video/mxs/mxsfb.c +++ b/drivers/video/mxs/mxsfb.c @@ -1,20 +1,26 @@ /* - * Freescale STMP37XX/STMP378X framebuffer driver + * Freescale MXS framebuffer driver * * Author: Vitaly Wool <vital@embeddedalley.com> * - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: + * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> @@ -31,14 +37,10 @@ #include <linux/cpufreq.h> #include <mach/hardware.h> -#include <mach/regs-pinctrl.h> #include <mach/regs-lcdif.h> -#include <mach/regs-clkctrl.h> -#include <mach/regs-apbh.h> +#include <mach/clock.h> #include <mach/lcdif.h> -#include <mach/stmp3xxx.h> - #define NUM_SCREENS 1 enum { @@ -47,9 +49,9 @@ enum { F_REENABLE, }; -struct stmp3xxx_fb_data { +struct mxs_fb_data { struct fb_info info; - struct stmp3xxx_platform_fb_data *pdata; + struct mxs_platform_fb_data *pdata; struct work_struct work; struct mutex blank_mutex; u32 state; @@ -58,8 +60,8 @@ struct stmp3xxx_fb_data { ssize_t map_size; dma_addr_t phys_start; dma_addr_t cur_phys; - int dma_irq; - int err_irq; + int irq; + unsigned long regbase; void *virt_start; struct device *dev; wait_queue_head_t vsync_wait_q; @@ -68,31 +70,31 @@ struct stmp3xxx_fb_data { }; /* forward declaration */ -static int stmp3xxxfb_blank(int blank, struct fb_info *info); +static int mxsfb_blank(int blank, struct fb_info *info); static unsigned char *default_panel_name; -static struct stmp3xxx_fb_data *cdata; -static void init_timings(struct stmp3xxx_fb_data *data); +static struct mxs_fb_data *cdata; +static void init_timings(struct mxs_fb_data *data); -static void stmp3xxxfb_enable_controller(struct stmp3xxx_fb_data *data) +static void mxsfb_enable_controller(struct mxs_fb_data *data) { - struct stmp3xxx_platform_fb_entry *pentry = data->pdata->cur; + struct mxs_platform_fb_entry *pentry = data->pdata->cur; if (!data || !data->pdata || !data->pdata->cur) return; - stmp3xxx_init_lcdif(); + mxs_init_lcdif(); init_timings(data); pentry->init_panel(data->dev, data->phys_start, - data->info.fix.smem_len, data->pdata->cur); + data->info.fix.smem_len, data->pdata->cur); pentry->run_panel(); if (pentry->blank_panel) pentry->blank_panel(FB_BLANK_UNBLANK); } -static void stmp3xxxfb_disable_controller(struct stmp3xxx_fb_data *data) +static void mxsfb_disable_controller(struct mxs_fb_data *data) { - struct stmp3xxx_platform_fb_entry *pentry = data->pdata->cur; + struct mxs_platform_fb_entry *pentry = data->pdata->cur; if (!data || !data->pdata || !data->pdata->cur) return; @@ -105,9 +107,9 @@ static void stmp3xxxfb_disable_controller(struct stmp3xxx_fb_data *data) pentry->release_panel(data->dev, pentry); } -static void set_controller_state(struct stmp3xxx_fb_data *data, u32 state) +static void set_controller_state(struct mxs_fb_data *data, u32 state) { - struct stmp3xxx_platform_fb_entry *pentry = data->pdata->cur; + struct mxs_platform_fb_entry *pentry = data->pdata->cur; struct fb_info *info = &data->info; u32 old_state; @@ -122,7 +124,7 @@ static void set_controller_state(struct stmp3xxx_fb_data *data, u32 state) */ if (old_state != F_DISABLE) { data->state = F_DISABLE; - stmp3xxxfb_disable_controller(data); + mxsfb_disable_controller(data); } break; @@ -131,21 +133,21 @@ static void set_controller_state(struct stmp3xxx_fb_data *data, u32 state) * Re-enable the controller when panel changed. */ if (old_state == F_ENABLE) { - stmp3xxxfb_disable_controller(data); + mxsfb_disable_controller(data); pentry = data->pdata->cur = data->pdata->next; info->fix.smem_len = pentry->y_res * pentry->x_res * - pentry->bpp / 8; + pentry->bpp / 8; info->screen_size = info->fix.smem_len; memset((void *)info->screen_base, 0, info->screen_size); - stmp3xxxfb_enable_controller(data); + mxsfb_enable_controller(data); data->state = F_ENABLE; } else if (old_state == F_DISABLE) { pentry = data->pdata->cur = data->pdata->next; info->fix.smem_len = pentry->y_res * pentry->x_res * - pentry->bpp / 8; + pentry->bpp / 8; info->screen_size = info->fix.smem_len; memset((void *)info->screen_base, 0, info->screen_size); @@ -156,7 +158,7 @@ static void set_controller_state(struct stmp3xxx_fb_data *data, u32 state) case F_ENABLE: if (old_state != F_ENABLE) { data->state = F_ENABLE; - stmp3xxxfb_enable_controller(data); + mxsfb_enable_controller(data); } break; } @@ -164,19 +166,18 @@ static void set_controller_state(struct stmp3xxx_fb_data *data, u32 state) } -static void stmp3xxxfb_task(struct work_struct *work) +static void mxsfb_task(struct work_struct *work) { - struct stmp3xxx_fb_data *data = - container_of(work, struct stmp3xxx_fb_data, work); + struct mxs_fb_data *data = container_of(work, struct mxs_fb_data, work); u32 state = xchg(&data->task_state, -1); pr_debug("%s: state = %d, data->task_state = %d\n", - __func__, state, data->task_state); + __func__, state, data->task_state); set_controller_state(data, state); } -static void stmp3xxx_schedule_work(struct stmp3xxx_fb_data *data, u32 state) +static void mxs_schedule_work(struct mxs_fb_data *data, u32 state) { unsigned long flags; @@ -190,67 +191,61 @@ static void stmp3xxx_schedule_work(struct stmp3xxx_fb_data *data, u32 state) static irqreturn_t lcd_irq_handler(int irq, void *dev_id) { - struct stmp3xxx_fb_data *data = dev_id; - u32 status_lcd = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CTRL1); - u32 status_apbh = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1); + struct mxs_fb_data *data = dev_id; + u32 status_lcd = __raw_readl(data->regbase + HW_LCDIF_CTRL1); pr_debug("%s: irq %d\n", __func__, irq); - if (status_apbh & BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ) - __raw_writel(BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ, - REGS_APBH_BASE + HW_APBH_CTRL1_CLR); - if (status_lcd & BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ) { pr_debug("%s: VSYNC irq\n", __func__); data->vsync_count++; __raw_writel(BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + data->regbase + HW_LCDIF_CTRL1_CLR); wake_up_interruptible(&data->vsync_wait_q); } if (status_lcd & BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ) { pr_debug("%s: frame done irq\n", __func__); __raw_writel(BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + data->regbase + HW_LCDIF_CTRL1_CLR); data->vsync_count++; } if (status_lcd & BM_LCDIF_CTRL1_UNDERFLOW_IRQ) { pr_debug("%s: underflow irq\n", __func__); __raw_writel(BM_LCDIF_CTRL1_UNDERFLOW_IRQ, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + data->regbase + HW_LCDIF_CTRL1_CLR); } if (status_lcd & BM_LCDIF_CTRL1_OVERFLOW_IRQ) { pr_debug("%s: overflow irq\n", __func__); __raw_writel(BM_LCDIF_CTRL1_OVERFLOW_IRQ, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + data->regbase + HW_LCDIF_CTRL1_CLR); } return IRQ_HANDLED; } -static struct fb_var_screeninfo stmp3xxxfb_default __devinitdata = { - .activate = FB_ACTIVATE_TEST, - .height = -1, - .width = -1, - .pixclock = 20000, - .left_margin = 64, - .right_margin = 64, - .upper_margin = 32, - .lower_margin = 32, - .hsync_len = 64, - .vsync_len = 2, - .vmode = FB_VMODE_NONINTERLACED, +static struct fb_var_screeninfo mxsfb_default __devinitdata = { + .activate = FB_ACTIVATE_TEST, + .height = -1, + .width = -1, + .pixclock = 20000, + .left_margin = 64, + .right_margin = 64, + .upper_margin = 32, + .lower_margin = 32, + .hsync_len = 64, + .vsync_len = 2, + .vmode = FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo stmp3xxxfb_fix __devinitdata = { - .id = "stmp3xxxfb", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, +static struct fb_fix_screeninfo mxsfb_fix __devinitdata = { + .id = "mxsfb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, }; -int stmp3xxxfb_get_info(struct fb_var_screeninfo *var, - struct fb_fix_screeninfo *fix) +int mxsfb_get_info(struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) { if (!cdata) return -ENODEV; @@ -260,7 +255,7 @@ int stmp3xxxfb_get_info(struct fb_var_screeninfo *var, return 0; } -void stmp3xxxfb_cfg_pxp(int enable, dma_addr_t pxp_phys) +void mxsfb_cfg_pxp(int enable, dma_addr_t pxp_phys) { if (enable) cdata->pdata->cur->pan_display(pxp_phys); @@ -268,35 +263,34 @@ void stmp3xxxfb_cfg_pxp(int enable, dma_addr_t pxp_phys) cdata->pdata->cur->pan_display(cdata->cur_phys); } -static int stmp3xxxfb_mmap(struct fb_info *info, struct vm_area_struct *vma) +static int mxsfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + struct mxs_fb_data *data = (struct mxs_fb_data *)info; unsigned long off = vma->vm_pgoff << PAGE_SHIFT; if (off < info->fix.smem_len) return dma_mmap_writecombine(data->dev, vma, - data->virt_start, - data->phys_start, - info->fix.smem_len); + data->virt_start, + data->phys_start, + info->fix.smem_len); else return -EINVAL; } -static int stmp3xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) +static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) { if (regno >= 256) /* no. of hw registers */ return 1; /* - * Program hardware... do anything you want with transp - */ + * Program hardware... do anything you want with transp + */ /* grayscale works only partially under directcolor */ if (info->var.grayscale) { /* grayscale = 0.30*R + 0.59*G + 0.11*B */ - red = green = blue = - (red * 77 + green * 151 + blue * 28) >> 8; + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; } /* Directcolor: @@ -304,7 +298,7 @@ static int stmp3xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * var->{color}.length contains length of bitfield * {hardwarespecific} contains width of RAMDAC * cmap[X] is programmed to - * (X << red.offset) | (X << green.offset) | (X << blue.offset) + * (X << red.offset) | (X << green.offset) | (X << blue.offset) * RAMDAC[X] is programmed to (red, green, blue) * * Pseudocolor: @@ -318,8 +312,8 @@ static int stmp3xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, * var->{color}.offset contains start of bitfield * var->{color}.length contains length of bitfield * cmap is programmed to - * (red << red.offset) | (green << green.offset) | - * (blue << blue.offset) | (transp << transp.offset) + * (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) * RAMDAC does not exist */ #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) @@ -347,10 +341,10 @@ static int stmp3xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, return 1; ((u32 *) (info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset) | - (transp << info->var.transp.offset); + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); } return 0; } @@ -365,23 +359,21 @@ static inline u_long get_line_length(int xres_virtual, int bpp) return length; } -static int get_matching_pentry(struct stmp3xxx_platform_fb_entry *pentry, +static int get_matching_pentry(struct mxs_platform_fb_entry *pentry, void *data, int ret_prev) { struct fb_var_screeninfo *info = data; pr_debug("%s: %d:%d:%d vs %d:%d:%d\n", __func__, - pentry->x_res, pentry->y_res, pentry->bpp, - info->yres, info->xres, info->bits_per_pixel); + pentry->x_res, pentry->y_res, pentry->bpp, + info->yres, info->xres, info->bits_per_pixel); if (pentry->x_res == info->yres && pentry->y_res == info->xres && pentry->bpp == info->bits_per_pixel) ret_prev = (int)pentry; return ret_prev; } -static int get_matching_pentry_by_name( - struct stmp3xxx_platform_fb_entry *pentry, - void *data, - int ret_prev) +static int get_matching_pentry_by_name(struct mxs_platform_fb_entry *pentry, + void *data, int ret_prev) { unsigned char *name = data; if (!strcmp(pentry->name, name)) @@ -396,20 +388,17 @@ static int get_matching_pentry_by_name( * * XXX: REVISIT */ -static int stmp3xxxfb_set_par(struct fb_info *info) +static int mxsfb_set_par(struct fb_info *info) { - struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; - struct stmp3xxx_platform_fb_data *pdata = data->pdata; - struct stmp3xxx_platform_fb_entry *pentry; - pentry = (void *)stmp3xxx_lcd_iterate_pdata(pdata, - get_matching_pentry, - &info->var); + struct mxs_fb_data *data = (struct mxs_fb_data *)info; + struct mxs_platform_fb_data *pdata = data->pdata; + struct mxs_platform_fb_entry *pentry; + pentry = (void *)mxs_lcd_iterate_pdata(pdata, + get_matching_pentry, &info->var); dev_dbg(data->dev, "%s: xres %d, yres %d, bpp %d\n", __func__, - info->var.xres, - info->var.yres, - info->var.bits_per_pixel); + info->var.xres, info->var.yres, info->var.bits_per_pixel); if (!pentry) return -EINVAL; @@ -427,12 +416,11 @@ static int stmp3xxxfb_set_par(struct fb_info *info) return 0; } -static int stmp3xxxfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) +static int mxsfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { u32 line_length; - struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; - struct stmp3xxx_platform_fb_data *pdata = data->pdata; + struct mxs_fb_data *data = (struct mxs_fb_data *)info; + struct mxs_platform_fb_data *pdata = data->pdata; /* * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! @@ -446,7 +434,7 @@ static int stmp3xxxfb_check_var(struct fb_var_screeninfo *var, } pr_debug("%s: xres %d, yres %d, bpp %d\n", __func__, - var->xres, var->yres, var->bits_per_pixel); + var->xres, var->yres, var->bits_per_pixel); /* * Some very basic checks */ @@ -471,7 +459,7 @@ static int stmp3xxxfb_check_var(struct fb_var_screeninfo *var, if (line_length * var->yres_virtual > data->map_size) return -ENOMEM; - if (!stmp3xxx_lcd_iterate_pdata(pdata, get_matching_pentry, var)) + if (!mxs_lcd_iterate_pdata(pdata, get_matching_pentry, var)) return -EINVAL; if (var->bits_per_pixel == 16) { @@ -512,19 +500,19 @@ static int stmp3xxxfb_check_var(struct fb_var_screeninfo *var, return 0; } - -static int stmp3xxxfb_wait_for_vsync(u32 channel, struct fb_info *info) +static int mxsfb_wait_for_vsync(u32 channel, struct fb_info *info) { - struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + struct mxs_fb_data *data = (struct mxs_fb_data *)info; u32 count = data->vsync_count; int ret = 0; __raw_writel(BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); + data->regbase + HW_LCDIF_CTRL1_SET); ret = wait_event_interruptible_timeout(data->vsync_wait_q, - count != data->vsync_count, HZ / 10); + count != data->vsync_count, + HZ / 10); __raw_writel(BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN, - REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); + data->regbase + HW_LCDIF_CTRL1_CLR); if (!ret) { dev_err(data->dev, "wait for vsync timed out\n"); ret = -ETIMEDOUT; @@ -532,8 +520,8 @@ static int stmp3xxxfb_wait_for_vsync(u32 channel, struct fb_info *info) return ret; } -static int stmp3xxxfb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) +static int mxsfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) { u32 channel = 0; int ret = -EINVAL; @@ -541,7 +529,7 @@ static int stmp3xxxfb_ioctl(struct fb_info *info, unsigned int cmd, switch (cmd) { case FBIO_WAITFORVSYNC: if (!get_user(channel, (__u32 __user *) arg)) - ret = stmp3xxxfb_wait_for_vsync(channel, info); + ret = mxsfb_wait_for_vsync(channel, info); break; default: break; @@ -549,9 +537,9 @@ static int stmp3xxxfb_ioctl(struct fb_info *info, unsigned int cmd, return ret; } -static int stmp3xxxfb_blank(int blank, struct fb_info *info) +static int mxsfb_blank(int blank, struct fb_info *info) { - struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + struct mxs_fb_data *data = (struct mxs_fb_data *)info; int ret = 0; switch (blank) { @@ -560,12 +548,12 @@ static int stmp3xxxfb_blank(int blank, struct fb_info *info) case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: pr_debug("%s: FB_BLANK_POWERDOWN\n", __func__); - stmp3xxx_schedule_work(data, F_DISABLE); + mxs_schedule_work(data, F_DISABLE); break; case FB_BLANK_UNBLANK: pr_debug("%s: FB_BLANK_UNBLANK\n", __func__); - stmp3xxx_schedule_work(data, F_ENABLE); + mxs_schedule_work(data, F_ENABLE); break; default: @@ -574,14 +562,14 @@ static int stmp3xxxfb_blank(int blank, struct fb_info *info) return ret; } -static int stmp3xxxfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) +static int mxsfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { - struct stmp3xxx_fb_data *data = (struct stmp3xxx_fb_data *)info; + struct mxs_fb_data *data = (struct mxs_fb_data *)info; int ret = 0; pr_debug("%s: var->xoffset %d, info->var.xoffset %d\n", - __func__, var->xoffset, info->var.xoffset); + __func__, var->xoffset, info->var.xoffset); /* check if var is valid; also, xpan is not supported */ if (!var || (var->xoffset != info->var.xoffset) || (var->yoffset + var->yres > var->yres_virtual)) { @@ -596,27 +584,27 @@ static int stmp3xxxfb_pan_display(struct fb_var_screeninfo *var, /* update framebuffer visual */ data->cur_phys = data->phys_start + - info->fix.line_length * var->yoffset; + info->fix.line_length * var->yoffset; data->pdata->cur->pan_display(data->cur_phys); out: return ret; } -static struct fb_ops stmp3xxxfb_ops = { +static struct fb_ops mxsfb_ops = { .owner = THIS_MODULE, - .fb_check_var = stmp3xxxfb_check_var, - .fb_set_par = stmp3xxxfb_set_par, - .fb_mmap = stmp3xxxfb_mmap, - .fb_setcolreg = stmp3xxxfb_setcolreg, - .fb_ioctl = stmp3xxxfb_ioctl, - .fb_blank = stmp3xxxfb_blank, - .fb_pan_display = stmp3xxxfb_pan_display, + .fb_check_var = mxsfb_check_var, + .fb_set_par = mxsfb_set_par, + .fb_mmap = mxsfb_mmap, + .fb_setcolreg = mxsfb_setcolreg, + .fb_ioctl = mxsfb_ioctl, + .fb_blank = mxsfb_blank, + .fb_pan_display = mxsfb_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, }; -static void init_timings(struct stmp3xxx_fb_data *data) +static void init_timings(struct mxs_fb_data *data) { unsigned phase_time; unsigned timings; @@ -628,23 +616,23 @@ static void init_timings(struct stmp3xxx_fb_data *data) timings = phase_time; timings |= timings << 8; timings |= timings << 16; - __raw_writel(timings, REGS_LCDIF_BASE + HW_LCDIF_TIMING); + __raw_writel(timings, data->regbase + HW_LCDIF_TIMING); } #ifdef CONFIG_CPU_FREQ -struct stmp3xxxfb_notifier_block { - struct stmp3xxx_fb_data *fb_data; +struct mxsfb_notifier_block { + struct mxs_fb_data *fb_data; struct notifier_block nb; }; -static int stmp3xxxfb_notifier(struct notifier_block *self, - unsigned long phase, void *p) +static int mxsfb_notifier(struct notifier_block *self, + unsigned long phase, void *p) { - struct stmp3xxxfb_notifier_block *block = - container_of(self, struct stmp3xxxfb_notifier_block, nb); - struct stmp3xxx_fb_data *data = block->fb_data; - struct stmp3xxx_platform_fb_entry *pentry = data->pdata->cur; + struct mxsfb_notifier_block *block = + container_of(self, struct mxsfb_notifier_block, nb); + struct mxs_fb_data *data = block->fb_data; + struct mxs_platform_fb_entry *pentry = data->pdata->cur; u32 old_state = data->state; if (!data || !data->pdata || !data->pdata->cur) @@ -671,31 +659,31 @@ static int stmp3xxxfb_notifier(struct notifier_block *self, return NOTIFY_DONE; } -static struct stmp3xxxfb_notifier_block stmp3xxxfb_nb = { +static struct mxsfb_notifier_block mxsfb_nb = { .nb = { - .notifier_call = stmp3xxxfb_notifier, - }, + .notifier_call = mxsfb_notifier, + }, }; #endif /* CONFIG_CPU_FREQ */ -static int get_max_memsize(struct stmp3xxx_platform_fb_entry *pentry, +static int get_max_memsize(struct mxs_platform_fb_entry *pentry, void *data, int ret_prev) { - struct stmp3xxx_fb_data *fbdata = data; + struct mxs_fb_data *fbdata = data; int sz = pentry->x_res * pentry->y_res * pentry->bpp / 8; fbdata->mem_size = sz < ret_prev ? ret_prev : sz; pr_debug("%s: mem_size now %d\n", __func__, fbdata->mem_size); return fbdata->mem_size; } -static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) +static int __devinit mxsfb_probe(struct platform_device *pdev) { int ret = 0; - struct stmp3xxx_fb_data *data; + struct mxs_fb_data *data; struct resource *res; struct fb_info *info; - struct stmp3xxx_platform_fb_data *pdata = pdev->dev.platform_data; - struct stmp3xxx_platform_fb_entry *pentry; + struct mxs_platform_fb_data *pdata = pdev->dev.platform_data; + struct mxs_platform_fb_entry *pentry = NULL; if (pdata == NULL) { ret = -ENODEV; @@ -703,11 +691,11 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) } if (default_panel_name) { - pentry = (void *)stmp3xxx_lcd_iterate_pdata(pdata, - get_matching_pentry_by_name, - default_panel_name); + pentry = (void *)mxs_lcd_iterate_pdata(pdata, + get_matching_pentry_by_name, + default_panel_name); if (pentry) { - stmp3xxx_lcd_move_pentry_up(pentry, pdata); + mxs_lcd_move_pentry_up(pentry, pdata); pdata->cur = pentry; } } @@ -719,10 +707,11 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) goto out; } - data = (struct stmp3xxx_fb_data *)framebuffer_alloc( - sizeof(struct stmp3xxx_fb_data) + - sizeof(u32) * 256 - - sizeof(struct fb_info), &pdev->dev); + data = + (struct mxs_fb_data *)framebuffer_alloc(sizeof(struct mxs_fb_data) + + sizeof(u32) * 256 - + sizeof(struct fb_info), + &pdev->dev); if (data == NULL) { ret = -ENOMEM; goto out; @@ -737,15 +726,15 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "resolution %dx%d, bpp %d\n", pentry->x_res, pentry->y_res, pentry->bpp); - stmp3xxx_lcd_iterate_pdata(pdata, get_max_memsize, data); + mxs_lcd_iterate_pdata(pdata, get_max_memsize, data); data->map_size = PAGE_ALIGN(data->mem_size) * NUM_SCREENS; dev_dbg(&pdev->dev, "memory to allocate: %d\n", data->map_size); data->virt_start = dma_alloc_writecombine(&pdev->dev, - data->map_size, - &data->phys_start, - GFP_KERNEL); + data->map_size, + &data->phys_start, + GFP_KERNEL); if (data->virt_start == NULL) { ret = -ENOMEM; @@ -754,44 +743,43 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "allocated at %p:0x%x\n", data->virt_start, data->phys_start); mutex_init(&data->blank_mutex); - INIT_WORK(&data->work, stmp3xxxfb_task); + INIT_WORK(&data->work, mxsfb_task); data->state = F_ENABLE; - stmp3xxxfb_default.bits_per_pixel = pentry->bpp; + mxsfb_default.bits_per_pixel = pentry->bpp; /* NB: rotated */ - stmp3xxxfb_default.xres = pentry->y_res; - stmp3xxxfb_default.yres = pentry->x_res; - stmp3xxxfb_default.xres_virtual = pentry->y_res; - stmp3xxxfb_default.yres_virtual = data->map_size / - (pentry->y_res * pentry->bpp / 8); - if (stmp3xxxfb_default.yres_virtual >= stmp3xxxfb_default.yres * 2) - stmp3xxxfb_default.yres_virtual = stmp3xxxfb_default.yres * 2; + mxsfb_default.xres = pentry->y_res; + mxsfb_default.yres = pentry->x_res; + mxsfb_default.xres_virtual = pentry->y_res; + mxsfb_default.yres_virtual = data->map_size / + (pentry->y_res * pentry->bpp / 8); + if (mxsfb_default.yres_virtual >= mxsfb_default.yres * 2) + mxsfb_default.yres_virtual = mxsfb_default.yres * 2; else - stmp3xxxfb_default.yres_virtual = stmp3xxxfb_default.yres; + mxsfb_default.yres_virtual = mxsfb_default.yres; - stmp3xxxfb_fix.smem_start = data->phys_start; - stmp3xxxfb_fix.smem_len = pentry->y_res * pentry->x_res * pentry->bpp / - 8; - stmp3xxxfb_fix.ypanstep = 1; + mxsfb_fix.smem_start = data->phys_start; + mxsfb_fix.smem_len = pentry->y_res * pentry->x_res * pentry->bpp / 8; + mxsfb_fix.ypanstep = 1; switch (pentry->bpp) { case 32: case 24: - stmp3xxxfb_default.red.offset = 16; - stmp3xxxfb_default.red.length = 8; - stmp3xxxfb_default.green.offset = 8; - stmp3xxxfb_default.green.length = 8; - stmp3xxxfb_default.blue.offset = 0; - stmp3xxxfb_default.blue.length = 8; + mxsfb_default.red.offset = 16; + mxsfb_default.red.length = 8; + mxsfb_default.green.offset = 8; + mxsfb_default.green.length = 8; + mxsfb_default.blue.offset = 0; + mxsfb_default.blue.length = 8; break; case 16: - stmp3xxxfb_default.red.offset = 11; - stmp3xxxfb_default.red.length = 5; - stmp3xxxfb_default.green.offset = 5; - stmp3xxxfb_default.green.length = 6; - stmp3xxxfb_default.blue.offset = 0; - stmp3xxxfb_default.blue.length = 5; + mxsfb_default.red.offset = 11; + mxsfb_default.red.length = 5; + mxsfb_default.green.offset = 5; + mxsfb_default.green.length = 6; + mxsfb_default.blue.offset = 0; + mxsfb_default.blue.length = 5; break; default: @@ -801,9 +789,9 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) } info->screen_base = data->virt_start; - info->fbops = &stmp3xxxfb_ops; - info->var = stmp3xxxfb_default; - info->fix = stmp3xxxfb_fix; + info->fbops = &mxsfb_ops; + info->var = mxsfb_default; + info->fix = mxsfb_fix; info->pseudo_palette = &data->par; data->par = NULL; info->flags = FBINFO_FLAG_DEFAULT; @@ -811,29 +799,33 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) init_waitqueue_head(&data->vsync_wait_q); data->vsync_count = 0; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "cannot get IRQ resource\n"); ret = -ENODEV; goto out_dma; } - data->dma_irq = res->start; + data->regbase = (unsigned long)IO_ADDRESS(res->start); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { dev_err(&pdev->dev, "cannot get IRQ resource\n"); ret = -ENODEV; goto out_dma; } - data->err_irq = res->start; + data->irq = res->start; + + mxsfb_check_var(&info->var, info); ret = fb_alloc_cmap(&info->cmap, 256, 0); if (ret) goto out_cmap; - stmp3xxx_init_lcdif(); + mxsfb_set_par(info); + + mxs_init_lcdif(); ret = pentry->init_panel(data->dev, data->phys_start, - stmp3xxxfb_fix.smem_len, pentry); + mxsfb_fix.smem_len, pentry); if (ret) { dev_err(&pdev->dev, "cannot initialize LCD panel\n"); goto out_panel; @@ -841,21 +833,15 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "LCD panel initialized\n"); init_timings(data); - ret = request_irq(data->dma_irq, lcd_irq_handler, 0, "fb_dma", data); + ret = request_irq(data->irq, lcd_irq_handler, 0, "fb_irq", data); if (ret) { dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", - data->dma_irq, ret); + data->irq, ret); goto out_panel; } - ret = request_irq(data->err_irq, lcd_irq_handler, 0, "fb_error", data); - if (ret) { - dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", - data->err_irq, ret); - goto out_irq; - } ret = register_framebuffer(info); if (ret) - goto out_register; + goto out_irq; pentry->run_panel(); dev_dbg(&pdev->dev, "LCD DMA channel has been started\n"); @@ -863,91 +849,87 @@ static int __devinit stmp3xxxfb_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "LCD running now\n"); #ifdef CONFIG_CPU_FREQ - stmp3xxxfb_nb.fb_data = data; - cpufreq_register_notifier(&stmp3xxxfb_nb.nb, - CPUFREQ_TRANSITION_NOTIFIER); + mxsfb_nb.fb_data = data; + cpufreq_register_notifier(&mxsfb_nb.nb, CPUFREQ_TRANSITION_NOTIFIER); #endif /* CONFIG_CPU_FREQ */ goto out; -out_register: - free_irq(data->err_irq, data); out_irq: - free_irq(data->dma_irq, data); + free_irq(data->irq, data); out_panel: fb_dealloc_cmap(&info->cmap); out_cmap: dma_free_writecombine(&pdev->dev, data->map_size, data->virt_start, - data->phys_start); + data->phys_start); out_dma: kfree(data); out: return ret; } -static int stmp3xxxfb_remove(struct platform_device *pdev) +static int mxsfb_remove(struct platform_device *pdev) { - struct stmp3xxx_fb_data *data = platform_get_drvdata(pdev); + struct mxs_fb_data *data = platform_get_drvdata(pdev); set_controller_state(data, F_DISABLE); unregister_framebuffer(&data->info); framebuffer_release(&data->info); fb_dealloc_cmap(&data->info.cmap); - free_irq(data->dma_irq, data); - free_irq(data->err_irq, data); + free_irq(data->irq, data); dma_free_writecombine(&pdev->dev, data->map_size, data->virt_start, - data->phys_start); + data->phys_start); kfree(data); platform_set_drvdata(pdev, NULL); return 0; } #ifdef CONFIG_PM -static int stmp3xxxfb_suspend(struct platform_device *pdev, pm_message_t state) +static int mxsfb_suspend(struct platform_device *pdev, pm_message_t state) { - struct stmp3xxx_fb_data *data = platform_get_drvdata(pdev); + struct mxs_fb_data *data = platform_get_drvdata(pdev); set_controller_state(data, F_DISABLE); return 0; } -static int stmp3xxxfb_resume(struct platform_device *pdev) +static int mxsfb_resume(struct platform_device *pdev) { - struct stmp3xxx_fb_data *data = platform_get_drvdata(pdev); + struct mxs_fb_data *data = platform_get_drvdata(pdev); set_controller_state(data, F_ENABLE); return 0; } #else -#define stmp3xxxfb_suspend NULL -#define stmp3xxxfb_resume NULL +#define mxsfb_suspend NULL +#define mxsfb_resume NULL #endif -static struct platform_driver stmp3xxxfb_driver = { - .probe = stmp3xxxfb_probe, - .remove = stmp3xxxfb_remove, - .suspend = stmp3xxxfb_suspend, - .resume = stmp3xxxfb_resume, - .driver = { - .name = "stmp3xxx-fb", - .owner = THIS_MODULE, - }, +static struct platform_driver mxsfb_driver = { + .probe = mxsfb_probe, + .remove = mxsfb_remove, + .suspend = mxsfb_suspend, + .resume = mxsfb_resume, + .driver = { + .name = "mxs-fb", + .owner = THIS_MODULE, + }, }; -static int __init stmp3xxxfb_init(void) +static int __init mxsfb_init(void) { - return platform_driver_register(&stmp3xxxfb_driver); + return platform_driver_register(&mxsfb_driver); } -static void __exit stmp3xxxfb_exit(void) +static void __exit mxsfb_exit(void) { - platform_driver_unregister(&stmp3xxxfb_driver); + platform_driver_unregister(&mxsfb_driver); } -module_init(stmp3xxxfb_init); -module_exit(stmp3xxxfb_exit); +module_init(mxsfb_init); +module_exit(mxsfb_exit); /* * LCD panel select @@ -957,8 +939,9 @@ static int __init default_panel_select(char *str) default_panel_name = str; return 0; } + __setup("lcd_panel=", default_panel_select); MODULE_AUTHOR("Vitaly Wool <vital@embeddedalley.com>"); -MODULE_DESCRIPTION("STMP3xxx Framebuffer Driver"); +MODULE_DESCRIPTION("MXS Framebuffer Driver"); MODULE_LICENSE("GPL"); |