ENGR00121272-2 [MX23] porting lcdif and framebuffer driver to new MSL

porting LMS430 lcd panel driver, and adjust mxs lcdif and framebuffer for MX23

Signed-off-by: Robby Cai <R63905@freescale.com>
This commit is contained in:
Robby Cai
2010-03-08 20:50:58 +08:00
committed by Matt Sealey
parent dcc8f69c10
commit 94b23ff390
7 changed files with 102 additions and 159 deletions

View File

@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <mach/device.h>
#include <mach/hardware.h>
#include "regs-lcdif.h"

View File

@@ -268,7 +268,7 @@ config BACKLIGHT_STMP37XX
config BACKLIGHT_MXS
tristate "Freescale MXS Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE && ARCH_MX28
depends on BACKLIGHT_CLASS_DEVICE && ARCH_MXS
default y
help
If you have a MXS, say y to enable the backlight driver.

View File

@@ -1,6 +1,6 @@
config FB_MXS
tristate "MXS Framebuffer driver"
depends on FB && ARCH_MX28
depends on FB && ARCH_MXS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -12,4 +12,11 @@ config FB_MXS
config FB_MXS_LCD_43WVF1G
depends on FB_MXS
tristate "SEIKO 4.3' LCD WVGA(800x480) PANEL"
default y
default y if ARCH_MX28
config FB_MXS_LCD_LMS430
depends on FB_MXS
bool "LMS430"
default y if ARCH_MX23
---help---
Use LMS430 dotclock LCD panel for MXS

View File

@@ -1,3 +1,4 @@
obj-$(CONFIG_ARCH_MXS) += lcdif.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_MXS_LCD_43WVF1G) += lcd_43wvf1g.o
obj-$(CONFIG_FB_MXS_LCD_LMS430) += lcd_lms430.o

View File

@@ -1,38 +1,39 @@
/*
* Freescale STMP378X Samsung LMS430 LCD panel initialization
* Freescale MXS Samsung LMS430 LCD panel initialization
*
* Embedded Alley Solutions, Inc <source@embeddedalley.com>
*
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc.
* Copyright 2009 Embedded Alley Solutions, Inc All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.
*/
/*
* 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:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#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/regs-lcdif.h>
#include <mach/regs-lradc.h>
#include <mach/regs-pinctrl.h>
#include <mach/regs-clkctrl.h>
#include <mach/regs-pwm.h>
#include <mach/regs-apbh.h>
#include <mach/gpio.h>
#include <mach/pins.h>
#include <mach/device.h>
#include <mach/lcdif.h>
#include <mach/pinmux.h>
#include <mach/stmp3xxx.h>
#include <mach/platform.h>
#include <mach/regs-pwm.h>
#include <mach/system.h>
#define REGS_PWM_BASE IO_ADDRESS(PWM_PHYS_ADDR)
#define DOTCLK_H_ACTIVE 480
#define DOTCLK_H_PULSE_WIDTH 1
@@ -41,85 +42,36 @@
#define DOTCLK_H_WAIT_CNT (DOTCLK_H_PULSE_WIDTH + (3 * DOTCLK_HB_PORCH))
#define DOTCLK_H_PERIOD (DOTCLK_H_WAIT_CNT + DOTCLK_HF_PORCH + DOTCLK_H_ACTIVE)
#define DOTCLK_V_PULSE_WIDTH 1
#define DOTCLK_V_ACTIVE 272
#define DOTCLK_V_PULSE_WIDTH 1
#define DOTCLK_VF_PORCH 4
#define DOTCLK_VB_PORCH 12
#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 stmp3xxx_platform_bl_data bl_data;
extern struct pin_group lcd_pins;
extern unsigned lcd_spi_pins[];
static int init_pinmux(void)
{
return stmp3xxx_request_pin_group(&lcd_pins, "lcd_lms430");
}
static int init_pinmux_spi(void)
{
int ret = -EINVAL;
ret = gpio_request(lcd_spi_pins[SPI_MOSI], "lcd_lms430");
if (ret)
goto out_1;
ret = gpio_request(lcd_spi_pins[SPI_SCLK], "lcd_lms430");
if (ret)
goto out_2;
ret = gpio_request(lcd_spi_pins[SPI_CS], "lcd_lms430");
if (ret)
goto out_3;
/* Enable these pins as outputs */
gpio_direction_output(lcd_spi_pins[SPI_MOSI], 1);
gpio_direction_output(lcd_spi_pins[SPI_SCLK], 1);
gpio_direction_output(lcd_spi_pins[SPI_CS], 1);
return 0;
out_3:
gpio_free(lcd_spi_pins[SPI_SCLK]);
out_2:
gpio_free(lcd_spi_pins[SPI_MOSI]);
out_1:
return ret;
}
static void uninit_pinmux(void)
{
stmp3xxx_release_pin_group(&lcd_pins, "lcd_lms430");
}
static void uninit_pinmux_spi(void)
{
gpio_free(lcd_spi_pins[SPI_MOSI]);
gpio_free(lcd_spi_pins[SPI_SCLK]);
gpio_free(lcd_spi_pins[SPI_CS]);
}
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 stmp3xxx_platform_fb_entry *pentry)
struct mxs_platform_fb_entry *pentry)
{
int ret = 0;
lcd_clk = clk_get(dev, "lcdif");
lcd_clk = clk_get(NULL, "lcdif");
if (IS_ERR(lcd_clk)) {
ret = PTR_ERR(lcd_clk);
goto out_1;
goto out;
}
ret = clk_enable(lcd_clk);
if (ret) {
clk_put(lcd_clk);
goto out_1;
goto out;
}
ret = clk_set_rate(lcd_clk, 1000000 / pentry->cycle_time_ns); /* kHz */
ret = clk_set_rate(lcd_clk, 1000000000 / pentry->cycle_time_ns); /* Hz */
if (ret) {
clk_disable(lcd_clk);
clk_put(lcd_clk);
goto out_1;
goto out;
}
/*
@@ -127,55 +79,43 @@ static int init_panel(struct device *dev, dma_addr_t phys, int memsize,
* First make it low for 100 msec, hi for 10 msec, low for 10 msec,
* then hi.
*/
stmp3xxx_clearl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); /* low */
__raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR); /* low */
mdelay(100);
stmp3xxx_setl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); /* high */
__raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); /* high */
mdelay(10);
stmp3xxx_clearl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); /* low */
__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);
stmp3xxx_setl(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1); /* high */
__raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET); /* high */
mdelay(1);
ret = init_pinmux();
if (ret)
goto out_1;
ret = init_pinmux_spi();
if (ret)
goto out_2;
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 = stmp3xxx_lcdif_dma_init(dev, phys, memsize, 1);
ret = mxs_lcdif_dma_init(dev, phys, memsize);
if (ret)
goto out_3;
goto out;
stmp3xxx_lcd_set_bl_pdata(pentry->bl_data);
stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_INIT, pentry);
mxs_lcd_set_bl_pdata(pentry->bl_data);
mxs_lcdif_notify_clients(MXS_LCDIF_PANEL_INIT, pentry);
return 0;
out_3:
uninit_pinmux_spi();
out_2:
uninit_pinmux();
out_1:
out:
return ret;
}
static void release_panel(struct device *dev,
struct stmp3xxx_platform_fb_entry *pentry)
struct mxs_platform_fb_entry *pentry)
{
stmp3xxx_lcdif_notify_clients(STMP3XXX_LCDIF_PANEL_RELEASE, pentry);
uninit_pinmux_spi();
uninit_pinmux();
mxs_lcdif_notify_clients(MXS_LCDIF_PANEL_RELEASE, pentry);
release_dotclk_panel();
stmp3xxx_lcdif_dma_release();
mxs_lcdif_dma_release();
clk_disable(lcd_clk);
clk_put(lcd_clk);
}
@@ -189,8 +129,8 @@ static int blank_panel(int blank)
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_POWERDOWN:
stmp3xxx_clearl(BM_LCDIF_CTRL_BYPASS_COUNT,
REGS_LCDIF_BASE + HW_LCDIF_CTRL);
__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)
@@ -200,8 +140,8 @@ static int blank_panel(int blank)
break;
case FB_BLANK_UNBLANK:
stmp3xxx_setl(BM_LCDIF_CTRL_BYPASS_COUNT,
REGS_LCDIF_BASE + HW_LCDIF_CTRL);
__raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT,
REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
break;
default:
@@ -210,75 +150,61 @@ static int blank_panel(int blank)
return ret;
}
static struct stmp3xxx_platform_fb_entry fb_entry = {
static struct mxs_platform_fb_entry fb_entry = {
.name = "lms430",
.x_res = 272,
.y_res = 480,
.bpp = 32,
.cycle_time_ns = 150,
.lcd_type = STMP3XXX_LCD_PANEL_DOTCLK,
.lcd_type = MXS_LCD_PANEL_DOTCLK,
.init_panel = init_panel,
.release_panel = release_panel,
.blank_panel = blank_panel,
.run_panel = stmp3xxx_lcdif_run,
.stop_panel = stmp3xxx_lcdif_stop,
.pan_display = stmp3xxx_lcdif_pan_display,
.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 stmp3xxx_platform_bl_data *data)
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);
goto out;
return ret;
}
clk_enable(pwm_clk);
stmp3xxx_reset_block(REGS_PWM_BASE, 1);
mxs_reset_block(REGS_PWM_BASE, 1);
ret = stmp3xxx_request_pin(PINID_PWM2, PIN_FUN1, "lcd_lms430");
if (ret)
goto out_mux;
stmp3xxx_pin_voltage(PINID_PWM2, PIN_8MA, "lcd_lms430");
stmp3xxx_pin_strength(PINID_PWM2, PIN_3_3V, "lcd_lms430");
__raw_writel(BF(0, PWM_ACTIVEn_INACTIVE) |
BF(0, PWM_ACTIVEn_ACTIVE), REGS_PWM_BASE + HW_PWM_ACTIVEn(2));
__raw_writel(BF(6, PWM_PERIODn_CDIV) | /* divide by 64 */
BF(2, PWM_PERIODn_INACTIVE_STATE) | /* low */
BF(3, PWM_PERIODn_ACTIVE_STATE) | /* high */
BF(599, PWM_PERIODn_PERIOD),
__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));
stmp3xxx_setl(BM_PWM_CTRL_PWM2_ENABLE, REGS_PWM_BASE + HW_PWM_CTRL);
__raw_writel(BM_PWM_CTRL_PWM2_ENABLE, REGS_PWM_BASE + HW_PWM_CTRL_SET);
return 0;
out_mux:
clk_put(pwm_clk);
out:
return ret;
}
static void free_bl(struct stmp3xxx_platform_bl_data *data)
static void free_bl(struct mxs_platform_bl_data *data)
{
__raw_writel(BF(0, PWM_ACTIVEn_INACTIVE) |
BF(0, PWM_ACTIVEn_ACTIVE),
__raw_writel(BF_PWM_ACTIVEn_INACTIVE(0) |
BF_PWM_ACTIVEn_ACTIVE(0),
REGS_PWM_BASE + HW_PWM_ACTIVEn(2));
__raw_writel(BF(6, PWM_PERIODn_CDIV) | /* divide by 64 */
BF(2, PWM_PERIODn_INACTIVE_STATE) | /* low */
BF(3, PWM_PERIODn_ACTIVE_STATE) | /* high */
BF(599, PWM_PERIODn_PERIOD),
__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));
stmp3xxx_clearl(BM_PWM_CTRL_PWM2_ENABLE, REGS_PWM_BASE + HW_PWM_CTRL);
stmp3xxx_pin_voltage(PINID_PWM2, PIN_4MA, "lcd_lms430");
stmp3xxx_pin_strength(PINID_PWM2, PIN_1_8V, "lcd_lms430");
__raw_writel(BM_PWM_CTRL_PWM2_ENABLE, REGS_PWM_BASE + HW_PWM_CTRL_CLR);
stmp3xxx_release_pin(PINID_PWM2, "lcd_lms430");
clk_disable(pwm_clk);
clk_put(pwm_clk);
}
@@ -306,7 +232,7 @@ static int bl_to_power(int br)
return base + (rem * (power[br / 10 + 1]) - base) / 10;
}
static int set_bl_intensity(struct stmp3xxx_platform_bl_data *data,
static int set_bl_intensity(struct mxs_platform_bl_data *data,
struct backlight_device *bd, int suspended)
{
int intensity = bd->props.brightness;
@@ -333,18 +259,18 @@ static int set_bl_intensity(struct stmp3xxx_platform_bl_data *data,
scaled_int += rem * (values[intensity / 10 + 1] -
values[intensity / 10]) / 10;
}
__raw_writel(BF(scaled_int, PWM_ACTIVEn_INACTIVE) |
BF(0, PWM_ACTIVEn_ACTIVE),
__raw_writel(BF_PWM_ACTIVEn_INACTIVE(scaled_int) |
BF_PWM_ACTIVEn_ACTIVE(0),
REGS_PWM_BASE + HW_PWM_ACTIVEn(2));
__raw_writel(BF(6, PWM_PERIODn_CDIV) | /* divide by 64 */
BF(2, PWM_PERIODn_INACTIVE_STATE) | /* low */
BF(3, PWM_PERIODn_ACTIVE_STATE) | /* high */
BF(399, PWM_PERIODn_PERIOD),
__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 stmp3xxx_platform_bl_data bl_data = {
static struct mxs_platform_bl_data bl_data = {
.bl_max_intensity = 100,
.bl_default_intensity = 50,
.bl_cons_intensity = 50,
@@ -355,8 +281,13 @@ static struct stmp3xxx_platform_bl_data bl_data = {
static int __init register_devices(void)
{
stmp3xxx_lcd_register_entry(&fb_entry,
stmp3xxx_framebuffer.dev.platform_data);
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;
}

View File

@@ -27,6 +27,7 @@
#include <mach/hardware.h>
#include <mach/lcdif.h>
#include <mach/regs-lcdif.h>
#include <mach/system.h>
#define REGS_LCDIF_BASE IO_ADDRESS(LCDIF_PHYS_ADDR)

View File

@@ -844,7 +844,9 @@ static int __devinit mxsfb_probe(struct platform_device *pdev)
goto out_irq;
pentry->run_panel();
dev_dbg(&pdev->dev, "LCD DMA channel has been started\n");
/* REVISIT: temporary workaround for MX23EVK */
mxsfb_disable_controller(data);
mxsfb_enable_controller(data);
data->cur_phys = data->phys_start;
dev_dbg(&pdev->dev, "LCD running now\n");