Commit e9ab3207 authored by Paul Mundt's avatar Paul Mundt

Merge branch 'for-paul-38-rebased' of git://gitorious.org/linux-omap-dss2/linux

parents e54be894 18faa1b6
......@@ -187,16 +187,19 @@ obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom.o \
board-zoom-peripherals.o \
board-zoom-display.o \
board-flash.o \
hsmmc.o \
board-zoom-debugboard.o
obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom.o \
board-zoom-peripherals.o \
board-zoom-display.o \
board-flash.o \
hsmmc.o \
board-zoom-debugboard.o
obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o \
board-zoom-peripherals.o \
board-zoom-display.o \
board-flash.o \
hsmmc.o
obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o \
......
......@@ -38,6 +38,7 @@
#include <plat/dma.h>
#include <plat/gpmc.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <plat/gpmc-smc91x.h>
......@@ -270,13 +271,18 @@ static struct omap_dss_device sdp3430_lcd_device = {
.platform_disable = sdp3430_panel_disable_lcd,
};
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = sdp3430_panel_enable_dvi,
.platform_disable = sdp3430_panel_disable_dvi,
};
static struct omap_dss_device sdp3430_dvi_device = {
.name = "dvi",
.driver_name = "generic_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.platform_enable = sdp3430_panel_enable_dvi,
.platform_disable = sdp3430_panel_disable_dvi,
};
static struct omap_dss_device sdp3430_tv_device = {
......
......@@ -207,6 +207,7 @@ static void __init omap_sdp_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
zoom_peripherals_init();
zoom_display_init();
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_sdp);
enable_board_wakeup_source();
......
......@@ -35,6 +35,7 @@
#include <plat/common.h>
#include <plat/usb.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include "mux.h"
#include "control.h"
......@@ -303,13 +304,18 @@ static void am3517_evm_panel_disable_lcd(struct omap_dss_device *dssdev)
lcd_enabled = 0;
}
static struct panel_generic_dpi_data lcd_panel = {
.name = "sharp_lq",
.platform_enable = am3517_evm_panel_enable_lcd,
.platform_disable = am3517_evm_panel_disable_lcd,
};
static struct omap_dss_device am3517_evm_lcd_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "lcd",
.driver_name = "sharp_lq_panel",
.driver_name = "generic_dpi_panel",
.data = &lcd_panel,
.phy.dpi.data_lines = 16,
.platform_enable = am3517_evm_panel_enable_lcd,
.platform_disable = am3517_evm_panel_disable_lcd,
};
static int am3517_evm_panel_enable_tv(struct omap_dss_device *dssdev)
......@@ -346,13 +352,18 @@ static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev)
dvi_enabled = 0;
}
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = am3517_evm_panel_enable_dvi,
.platform_disable = am3517_evm_panel_disable_dvi,
};
static struct omap_dss_device am3517_evm_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
.driver_name = "generic_panel",
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.platform_enable = am3517_evm_panel_enable_dvi,
.platform_disable = am3517_evm_panel_disable_dvi,
};
static struct omap_dss_device *am3517_evm_dss_devices[] = {
......
......@@ -46,6 +46,7 @@
#include <plat/gpmc.h>
#include <plat/usb.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <plat/mcspi.h>
#include <mach/hardware.h>
......@@ -351,22 +352,32 @@ static void cm_t35_panel_disable_tv(struct omap_dss_device *dssdev)
{
}
static struct panel_generic_dpi_data lcd_panel = {
.name = "toppoly_tdo35s",
.platform_enable = cm_t35_panel_enable_lcd,
.platform_disable = cm_t35_panel_disable_lcd,
};
static struct omap_dss_device cm_t35_lcd_device = {
.name = "lcd",
.driver_name = "toppoly_tdo35s_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &lcd_panel,
.phy.dpi.data_lines = 18,
.platform_enable = cm_t35_panel_enable_lcd,
.platform_disable = cm_t35_panel_disable_lcd,
};
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = cm_t35_panel_enable_dvi,
.platform_disable = cm_t35_panel_disable_dvi,
};
static struct omap_dss_device cm_t35_dvi_device = {
.name = "dvi",
.driver_name = "generic_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.platform_enable = cm_t35_panel_enable_dvi,
.platform_disable = cm_t35_panel_disable_dvi,
};
static struct omap_dss_device cm_t35_tv_device = {
......
......@@ -46,6 +46,7 @@
#include <plat/nand.h>
#include <plat/usb.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <plat/mcspi.h>
#include <linux/input/matrix_keypad.h>
......@@ -149,23 +150,32 @@ static struct regulator_consumer_supply devkit8000_vmmc1_supply =
static struct regulator_consumer_supply devkit8000_vio_supply =
REGULATOR_SUPPLY("vcc", "spi2.0");
static struct panel_generic_dpi_data lcd_panel = {
.name = "generic",
.platform_enable = devkit8000_panel_enable_lcd,
.platform_disable = devkit8000_panel_disable_lcd,
};
static struct omap_dss_device devkit8000_lcd_device = {
.name = "lcd",
.driver_name = "generic_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &lcd_panel,
.phy.dpi.data_lines = 24,
.reset_gpio = -EINVAL, /* will be replaced */
.platform_enable = devkit8000_panel_enable_lcd,
.platform_disable = devkit8000_panel_disable_lcd,
};
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = devkit8000_panel_enable_dvi,
.platform_disable = devkit8000_panel_disable_dvi,
};
static struct omap_dss_device devkit8000_dvi_device = {
.name = "dvi",
.driver_name = "generic_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.reset_gpio = -EINVAL, /* will be replaced */
.platform_enable = devkit8000_panel_enable_dvi,
.platform_disable = devkit8000_panel_disable_dvi,
};
static struct omap_dss_device devkit8000_tv_device = {
......
......@@ -31,6 +31,7 @@
#include <plat/gpmc.h>
#include <plat/usb.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <plat/onenand.h>
#include "mux.h"
......@@ -459,13 +460,18 @@ static void igep2_disable_dvi(struct omap_dss_device *dssdev)
gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0);
}
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = igep2_enable_dvi,
.platform_disable = igep2_disable_dvi,
};
static struct omap_dss_device igep2_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
.driver_name = "generic_panel",
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.platform_enable = igep2_enable_dvi,
.platform_disable = igep2_disable_dvi,
};
static struct omap_dss_device *igep2_dss_devices[] = {
......
......@@ -41,6 +41,7 @@
#include <plat/board.h>
#include <plat/common.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
......@@ -194,14 +195,19 @@ static void beagle_disable_dvi(struct omap_dss_device *dssdev)
gpio_set_value(dssdev->reset_gpio, 0);
}
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = beagle_enable_dvi,
.platform_disable = beagle_disable_dvi,
};
static struct omap_dss_device beagle_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
.driver_name = "generic_panel",
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.reset_gpio = 170,
.platform_enable = beagle_enable_dvi,
.platform_disable = beagle_disable_dvi,
};
static struct omap_dss_device beagle_tv_device = {
......
......@@ -43,6 +43,7 @@
#include <plat/common.h>
#include <plat/mcspi.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
......@@ -301,13 +302,18 @@ static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
dvi_enabled = 0;
}
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = omap3_evm_enable_dvi,
.platform_disable = omap3_evm_disable_dvi,
};
static struct omap_dss_device omap3_evm_dvi_device = {
.name = "dvi",
.driver_name = "generic_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.platform_enable = omap3_evm_enable_dvi,
.platform_disable = omap3_evm_disable_dvi,
};
static struct omap_dss_device *omap3_evm_dss_devices[] = {
......
......@@ -40,6 +40,7 @@
#include <plat/nand.h>
#include <plat/usb.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <plat/mcspi.h>
#include <linux/input/matrix_keypad.h>
......@@ -160,13 +161,18 @@ static void omap3_stalker_disable_lcd(struct omap_dss_device *dssdev)
lcd_enabled = 0;
}
static struct panel_generic_dpi_data lcd_panel = {
.name = "generic",
.platform_enable = omap3_stalker_enable_lcd,
.platform_disable = omap3_stalker_disable_lcd,
};
static struct omap_dss_device omap3_stalker_lcd_device = {
.name = "lcd",
.driver_name = "generic_panel",
.driver_name = "generic_dpi_panel",
.data = &lcd_panel,
.phy.dpi.data_lines = 24,
.type = OMAP_DISPLAY_TYPE_DPI,
.platform_enable = omap3_stalker_enable_lcd,
.platform_disable = omap3_stalker_disable_lcd,
};
static int omap3_stalker_enable_tv(struct omap_dss_device *dssdev)
......@@ -208,13 +214,18 @@ static void omap3_stalker_disable_dvi(struct omap_dss_device *dssdev)
dvi_enabled = 0;
}
static struct panel_generic_dpi_data dvi_panel = {
.name = "generic",
.platform_enable = omap3_stalker_enable_dvi,
.platform_disable = omap3_stalker_disable_dvi,
};
static struct omap_dss_device omap3_stalker_dvi_device = {
.name = "dvi",
.driver_name = "generic_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
.platform_enable = omap3_stalker_enable_dvi,
.platform_disable = omap3_stalker_disable_dvi,
};
static struct omap_dss_device *omap3_stalker_dss_devices[] = {
......
/*
* Copyright (C) 2010 Texas Instruments Inc.
*
* Modified from mach-omap2/board-zoom-peripherals.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/i2c/twl.h>
#include <linux/spi/spi.h>
#include <plat/mcspi.h>
#include <plat/display.h>
#define LCD_PANEL_RESET_GPIO_PROD 96
#define LCD_PANEL_RESET_GPIO_PILOT 55
#define LCD_PANEL_QVGA_GPIO 56
static void zoom_lcd_panel_init(void)
{
int ret;
unsigned char lcd_panel_reset_gpio;
lcd_panel_reset_gpio = (omap_rev() > OMAP3430_REV_ES3_0) ?
LCD_PANEL_RESET_GPIO_PROD :
LCD_PANEL_RESET_GPIO_PILOT;
ret = gpio_request(lcd_panel_reset_gpio, "lcd reset");
if (ret) {
pr_err("Failed to get LCD reset GPIO (gpio%d).\n",
lcd_panel_reset_gpio);
return;
}
gpio_direction_output(lcd_panel_reset_gpio, 1);
ret = gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
if (ret) {
pr_err("Failed to get LCD_PANEL_QVGA_GPIO (gpio%d).\n",
LCD_PANEL_QVGA_GPIO);
goto err0;
}
gpio_direction_output(LCD_PANEL_QVGA_GPIO, 1);
return;
err0:
gpio_free(lcd_panel_reset_gpio);
}
static int zoom_panel_enable_lcd(struct omap_dss_device *dssdev)
{
return 0;
}
static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev)
{
}
/*
* PWMA/B register offsets (TWL4030_MODULE_PWMA)
*/
#define TWL_INTBR_PMBR1 0xD
#define TWL_INTBR_GPBR1 0xC
#define TWL_LED_PWMON 0x0
#define TWL_LED_PWMOFF 0x1
static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level)
{
unsigned char c;
u8 mux_pwm, enb_pwm;
if (level > 100)
return -1;
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &mux_pwm, TWL_INTBR_PMBR1);
twl_i2c_read_u8(TWL4030_MODULE_INTBR, &enb_pwm, TWL_INTBR_GPBR1);
if (level == 0) {
/* disable pwm1 output and clock */
enb_pwm = enb_pwm & 0xF5;
/* change pwm1 pin to gpio pin */
mux_pwm = mux_pwm & 0xCF;
twl_i2c_write_u8(TWL4030_MODULE_INTBR,
enb_pwm, TWL_INTBR_GPBR1);
twl_i2c_write_u8(TWL4030_MODULE_INTBR,
mux_pwm, TWL_INTBR_PMBR1);
return 0;
}
if (!((enb_pwm & 0xA) && (mux_pwm & 0x30))) {
/* change gpio pin to pwm1 pin */
mux_pwm = mux_pwm | 0x30;
/* enable pwm1 output and clock*/
enb_pwm = enb_pwm | 0x0A;
twl_i2c_write_u8(TWL4030_MODULE_INTBR,
mux_pwm, TWL_INTBR_PMBR1);
twl_i2c_write_u8(TWL4030_MODULE_INTBR,
enb_pwm, TWL_INTBR_GPBR1);
}
c = ((50 * (100 - level)) / 100) + 1;
twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF);
twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON);
return 0;
}
static struct omap_dss_device zoom_lcd_device = {
.name = "lcd",
.driver_name = "NEC_8048_panel",
.type = OMAP_DISPLAY_TYPE_DPI,
.phy.dpi.data_lines = 24,
.platform_enable = zoom_panel_enable_lcd,
.platform_disable = zoom_panel_disable_lcd,
.max_backlight_level = 100,
.set_backlight = zoom_set_bl_intensity,
};
static struct omap_dss_device *zoom_dss_devices[] = {
&zoom_lcd_device,
};
static struct omap_dss_board_info zoom_dss_data = {
.num_devices = ARRAY_SIZE(zoom_dss_devices),
.devices = zoom_dss_devices,
.default_device = &zoom_lcd_device,
};
static struct platform_device zoom_dss_device = {
.name = "omapdss",
.id = -1,
.dev = {
.platform_data = &zoom_dss_data,
},
};
static struct omap2_mcspi_device_config dss_lcd_mcspi_config = {
.turbo_mode = 1,
.single_channel = 1, /* 0: slave, 1: master */
};
static struct spi_board_info nec_8048_spi_board_info[] __initdata = {
[0] = {
.modalias = "nec_8048_spi",
.bus_num = 1,
.chip_select = 2,
.max_speed_hz = 375000,
.controller_data = &dss_lcd_mcspi_config,
},
};
static struct platform_device *zoom_display_devices[] __initdata = {
&zoom_dss_device,
};
void __init zoom_display_init(void)
{
platform_add_devices(zoom_display_devices,
ARRAY_SIZE(zoom_display_devices));
spi_register_board_info(nec_8048_spi_board_info,
ARRAY_SIZE(nec_8048_spi_board_info));
zoom_lcd_panel_init();
}
......@@ -35,6 +35,8 @@
#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
/* Zoom2 has Qwerty keyboard*/
static uint32_t board_keymap[] = {
KEY(0, 0, KEY_E),
......@@ -224,9 +226,43 @@ static struct omap2_hsmmc_info mmc[] = {
{} /* Terminator */
};
static struct regulator_consumer_supply zoom_vpll2_supply =
REGULATOR_SUPPLY("vdds_dsi", "omapdss");
static struct regulator_consumer_supply zoom_vdda_dac_supply =
REGULATOR_SUPPLY("vdda_dac", "omapdss");
static struct regulator_init_data zoom_vpll2 = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &zoom_vpll2_supply,
};
static struct regulator_init_data zoom_vdac = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
.consumer_supplies = &zoom_vdda_dac_supply,
};
static int zoom_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
int ret;
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
mmc[0].gpio_cd = gpio + 0;
omap2_hsmmc_init(mmc);
......@@ -238,7 +274,15 @@ static int zoom_twl_gpio_setup(struct device *dev,
zoom_vsim_supply.dev = mmc[0].dev;
zoom_vmmc2_supply.dev = mmc[1].dev;
return 0;
ret = gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd enable");
if (ret) {
pr_err("Failed to get LCD_PANEL_ENABLE_GPIO (gpio%d).\n",
LCD_PANEL_ENABLE_GPIO);
return ret;
}
gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
return ret;
}
/* EXTMUTE callback function */
......@@ -301,7 +345,8 @@ static struct twl4030_platform_data zoom_twldata = {
.vmmc1 = &zoom_vmmc1,
.vmmc2 = &zoom_vmmc2,
.vsim = &zoom_vsim,
.vpll2 = &zoom_vpll2,
.vdac = &zoom_vdac,
};
static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
......
......@@ -130,6 +130,7 @@ static void __init omap_zoom_init(void)
ARRAY_SIZE(zoom_nand_partitions), ZOOM_NAND_CS);
zoom_debugboard_init();
zoom_peripherals_init();
zoom_display_init();
}
MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
......
/*
* Defines for zoom boards
*/
#include <plat/display.h>
#define ZOOM_NAND_CS 0
extern int __init zoom_debugboard_init(void);
extern void __init zoom_peripherals_init(void);
extern void __init zoom_display_init(void);
#define ZOOM2_HEADSET_EXTMUTE_GPIO 153
......@@ -42,6 +42,10 @@
#define DISPC_IRQ_SYNC_LOST (1 << 14)
#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15)
#define DISPC_IRQ_WAKEUP (1 << 16)
#define DISPC_IRQ_SYNC_LOST2 (1 << 17)
#define DISPC_IRQ_VSYNC2 (1 << 18)
#define DISPC_IRQ_ACBIAS_COUNT_STAT2 (1 << 21)
#define DISPC_IRQ_FRAMEDONE2 (1 << 22)
struct omap_dss_device;
struct omap_overlay_manager;
......@@ -64,6 +68,7 @@ enum omap_plane {
enum omap_channel {
OMAP_DSS_CHANNEL_LCD = 0,
OMAP_DSS_CHANNEL_DIGIT = 1,
OMAP_DSS_CHANNEL_LCD2 = 2,
};
enum omap_color_mode {
......@@ -142,6 +147,7 @@ enum omap_dss_display_state {
enum omap_dss_overlay_managers {
OMAP_DSS_OVL_MGR_LCD,
OMAP_DSS_OVL_MGR_TV,
OMAP_DSS_OVL_MGR_LCD2,
};
enum omap_dss_rotation_type {
......@@ -268,6 +274,7 @@ struct omap_overlay_info {
u16 out_width; /* if 0, out_width == width */
u16 out_height; /* if 0, out_height == height */
u8 global_alpha;
u8 pre_mult_alpha;
};
struct omap_overlay {
......@@ -351,6 +358,8 @@ struct omap_dss_device {
enum omap_display_type type;
enum omap_channel channel;
union {
struct {
u8 data_lines;
......
/*
* Header for generic DPI panel driver
*
* Copyright (C) 2010 Canonical Ltd.
* Author: Bryan Wu <bryan.wu@canonical.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
#define __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
#include "display.h"
/**
* struct panel_generic_dpi_data - panel driver configuration data
* @name: panel name
* @platform_enable: platform specific panel enable function
* @platform_disable: platform specific panel disable function
*/
struct panel_generic_dpi_data {
const char *name;
int (*platform_enable)(struct omap_dss_device *dssdev);
void (*platform_disable)(struct omap_dss_device *dssdev);
};
#endif /* __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H */
menu "OMAP2/3 Display Device Drivers"
depends on OMAP2_DSS
config PANEL_GENERIC
tristate "Generic Panel"
config PANEL_GENERIC_DPI
tristate "Generic DPI Panel"
help
Generic panel driver.
Used for DVI output for Beagle and OMAP3 SDP.
Generic DPI panel driver.
Supports DVI output for Beagle and OMAP3 SDP.
Supports LCD Panel used in TI SDP3430 and EVM boards,
OMAP3517 EVM boards and CM-T35.
config PANEL_SHARP_LS037V7DW01
tristate "Sharp LS037V7DW01 LCD Panel"
......@@ -14,11 +16,12 @@ config PANEL_SHARP_LS037V7DW01
help
LCD Panel used in TI's SDP3430 and EVM boards
config PANEL_SHARP_LQ043T1DG01
tristate "Sharp LQ043T1DG01 LCD Panel"
depends on OMAP2_DSS
help
LCD Panel used in TI's OMAP3517 EVM boards
config PANEL_NEC_NL8048HL11_01B
tristate "NEC NL8048HL11-01B Panel"
depends on OMAP2_DSS
help
This NEC NL8048HL11-01B panel is TFT LCD
used in the Zoom2/3/3630 sdp boards.
config PANEL_TAAL
tristate "Taal DSI Panel"
......@@ -26,12 +29,6 @@ config PANEL_TAAL
help
Taal DSI command mode panel from TPO.
config PANEL_TOPPOLY_TDO35S
tristate "Toppoly TDO35S LCD Panel support"
depends on OMAP2_DSS
help
LCD Panel used in CM-T35
config PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
depends on OMAP2_DSS && SPI
......
obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
/*
* Generic DPI Panels support
*
* Copyright (C) 2010 Canonical Ltd.
* Author: Bryan Wu <bryan.wu@canonical.com>
*
* LCD panel driver for Sharp LQ043T1DG01
*
* Copyright (C) 2009 Texas Instruments Inc
* Author: Vaibhav Hiremath <hvaibhav@ti.com>
*
* LCD panel driver for Toppoly TDO35S
*
* Copyright (C) 2009 CompuLab, Ltd.
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Copyright (C) 2008 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <plat/panel-generic-dpi.h>
struct panel_config {
struct omap_video_timings timings;
int acbi; /* ac-bias pin transitions per interrupt */
/* Unit: line clocks */
int acb; /* ac-bias pin frequency */
enum omap_panel_config config;
int power_on_delay;
int power_off_delay;
/*
* Used to match device to panel configuration
* when use generic panel driver
*/
const char *name;
};
/* Panel configurations */
static struct panel_config generic_dpi_panels[] = {
/* Generic Panel */
{
{
.x_res = 640,
.y_res = 480,
.pixel_clock = 23500,
.hfp = 48,
.hsw = 32,
.hbp = 80,
.vfp = 3,
.vsw = 4,
.vbp = 7,
},
.acbi = 0x0,
.acb = 0x0,
.config = OMAP_DSS_LCD_TFT,
.power_on_delay = 0,
.power_off_delay = 0,
.name = "generic",
},
/* Sharp LQ043T1DG01 */
{
{
.x_res = 480,
.y_res = 272,
.pixel_clock = 9000,
.hsw = 42,
.hfp = 3,
.hbp = 2,
.vsw = 11,
.vfp = 3,
.vbp = 2,
},
.acbi = 0x0,
.acb = 0x0,
.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
.power_on_delay = 50,
.power_off_delay = 100,
.name = "sharp_lq",
},
/* Sharp LS037V7DW01 */
{
{
.x_res = 480,
.y_res = 640,
.pixel_clock = 19200,
.hsw = 2,
.hfp = 1,
.hbp = 28,
.vsw = 1,
.vfp = 1,
.vbp = 1,
},
.acbi = 0x0,
.acb = 0x28,
.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS,
.power_on_delay = 50,
.power_off_delay = 100,
.name = "sharp_ls",
},
/* Toppoly TDO35S */
{
{
.x_res = 480,
.y_res = 640,
.pixel_clock = 26000,
.hfp = 104,
.hsw = 8,
.hbp = 8,
.vfp = 4,
.vsw = 2,
.vbp = 2,
},
.acbi = 0x0,
.acb = 0x0,
.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC |
OMAP_DSS_LCD_ONOFF,
.power_on_delay = 0,
.power_off_delay = 0,
.name = "toppoly_tdo35s",
},
};
struct panel_drv_data {
struct omap_dss_device *dssdev;
struct panel_config *panel_config;
};
static inline struct panel_generic_dpi_data
*get_panel_data(const struct omap_dss_device *dssdev)
{
return (struct panel_generic_dpi_data *) dssdev->data;
}
static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
struct panel_config *panel_config = drv_data->panel_config;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
/* wait couple of vsyncs until enabling the LCD */
if (panel_config->power_on_delay)
msleep(panel_config->power_on_delay);
if (panel_data->platform_enable) {
r = panel_data->platform_enable(dssdev);
if (r)
goto err1;
}
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
{
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
struct panel_config *panel_config = drv_data->panel_config;
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
if (panel_data->platform_disable)
panel_data->platform_disable(dssdev);
/* wait couple of vsyncs after disabling the LCD */
if (panel_config->power_off_delay)
msleep(panel_config->power_off_delay);
omapdss_dpi_display_disable(dssdev);
}
static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
{
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct panel_config *panel_config = NULL;
struct panel_drv_data *drv_data = NULL;
int i;
dev_dbg(&dssdev->dev, "probe\n");
if (!panel_data || !panel_data->name)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
panel_config = &generic_dpi_panels[i];
break;
}
}
if (!panel_config)
return -EINVAL;
dssdev->panel.config = panel_config->config;
dssdev->panel.timings = panel_config->timings;
dssdev->panel.acb = panel_config->acb;
dssdev->panel.acbi = panel_config->acbi;
drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
drv_data->dssdev = dssdev;
drv_data->panel_config = panel_config;
dev_set_drvdata(&dssdev->dev, drv_data);
return 0;
}
static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
{
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
dev_dbg(&dssdev->dev, "remove\n");
kfree(drv_data);
dev_set_drvdata(&dssdev->dev, NULL);
}
static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
r = generic_dpi_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
{
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
{
generic_dpi_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
{
int r = 0;
r = generic_dpi_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
dpi_set_timings(dssdev, timings);
}
static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
*timings = dssdev->panel.timings;
}
static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
return dpi_check_timings(dssdev, timings);
}
static struct omap_dss_driver dpi_driver = {
.probe = generic_dpi_panel_probe,
.remove = generic_dpi_panel_remove,
.enable = generic_dpi_panel_enable,
.disable = generic_dpi_panel_disable,
.suspend = generic_dpi_panel_suspend,
.resume = generic_dpi_panel_resume,
.set_timings = generic_dpi_panel_set_timings,
.get_timings = generic_dpi_panel_get_timings,
.check_timings = generic_dpi_panel_check_timings,
.driver = {
.name = "generic_dpi_panel",
.owner = THIS_MODULE,
},
};
static int __init generic_dpi_panel_drv_init(void)
{
return omap_dss_register_driver(&dpi_driver);
}
static void __exit generic_dpi_panel_drv_exit(void)
{
omap_dss_unregister_driver(&dpi_driver);
}
module_init(generic_dpi_panel_drv_init);
module_exit(generic_dpi_panel_drv_exit);
MODULE_LICENSE("GPL");
/*
* Generic panel support
*
* Copyright (C) 2008 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <plat/display.h>
static struct omap_video_timings generic_panel_timings = {
/* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
.x_res = 640,
.y_res = 480,
.pixel_clock = 23500,
.hfp = 48,
.hsw = 32,
.hbp = 80,
.vfp = 3,
.vsw = 4,
.vbp = 7,
};
static int generic_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
goto err1;
}
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
static void generic_panel_power_off(struct omap_dss_device *dssdev)
{
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
omapdss_dpi_display_disable(dssdev);
}
static int generic_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.config = OMAP_DSS_LCD_TFT;
dssdev->panel.timings = generic_panel_timings;
return 0;
}
static void generic_panel_remove(struct omap_dss_device *dssdev)
{
}
static int generic_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
r = generic_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void generic_panel_disable(struct omap_dss_device *dssdev)
{
generic_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int generic_panel_suspend(struct omap_dss_device *dssdev)
{
generic_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int generic_panel_resume(struct omap_dss_device *dssdev)
{
int r = 0;
r = generic_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void generic_panel_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
dpi_set_timings(dssdev, timings);
}
static void generic_panel_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
*timings = dssdev->panel.timings;
}
static int generic_panel_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
return dpi_check_timings(dssdev, timings);
}
static struct omap_dss_driver generic_driver = {
.probe = generic_panel_probe,
.remove = generic_panel_remove,
.enable = generic_panel_enable,
.disable = generic_panel_disable,
.suspend = generic_panel_suspend,
.resume = generic_panel_resume,
.set_timings = generic_panel_set_timings,
.get_timings = generic_panel_get_timings,
.check_timings = generic_panel_check_timings,
.driver = {
.name = "generic_panel",
.owner = THIS_MODULE,
},
};
static int __init generic_panel_drv_init(void)
{
return omap_dss_register_driver(&generic_driver);
}
static void __exit generic_panel_drv_exit(void)
{
omap_dss_unregister_driver(&generic_driver);
}
module_init(generic_panel_drv_init);
module_exit(generic_panel_drv_exit);
MODULE_LICENSE("GPL");
/*
* Support for NEC-nl8048hl11-01b panel driver
*
* Copyright (C) 2010 Texas Instruments Inc.
* Author: Erik Gilling <konkers@android.com>
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#include <plat/display.h>
#define LCD_XRES 800
#define LCD_YRES 480
/*
* NEC PIX Clock Ratings
* MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
*/
#define LCD_PIXEL_CLOCK 23800
struct nec_8048_data {
struct backlight_device *bl;
};
static const struct {
unsigned char addr;
unsigned char dat;
} nec_8048_init_seq[] = {
{ 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
{ 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
{ 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
{ 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
{ 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
{ 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
{ 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
{ 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
{ 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
{ 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
{ 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
{ 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
{ 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
{ 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
{ 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
{ 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
{ 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
{ 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
};
/*
* NEC NL8048HL11-01B Manual
* defines HFB, HSW, HBP, VFP, VSW, VBP as shown below
*/
static struct omap_video_timings nec_8048_panel_timings = {
/* 800 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
.x_res = LCD_XRES,
.y_res = LCD_YRES,
.pixel_clock = LCD_PIXEL_CLOCK,
.hfp = 6,
.hsw = 1,
.hbp = 4,
.vfp = 3,
.vsw = 1,
.vbp = 4,
};
static int nec_8048_bl_update_status(struct backlight_device *bl)
{
struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
int level;
if (!dssdev->set_backlight)
return -EINVAL;
if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
bl->props.power == FB_BLANK_UNBLANK)
level = bl->props.brightness;
else
level = 0;
return dssdev->set_backlight(dssdev, level);
}
static int nec_8048_bl_get_brightness(struct backlight_device *bl)
{
if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
bl->props.power == FB_BLANK_UNBLANK)
return bl->props.brightness;
return 0;
}
static const struct backlight_ops nec_8048_bl_ops = {
.get_brightness = nec_8048_bl_get_brightness,
.update_status = nec_8048_bl_update_status,
};
static int nec_8048_panel_probe(struct omap_dss_device *dssdev)
{
struct backlight_device *bl;
struct nec_8048_data *necd;
struct backlight_properties props;
int r;
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF |
OMAP_DSS_LCD_ONOFF;
dssdev->panel.timings = nec_8048_panel_timings;
necd = kzalloc(sizeof(*necd), GFP_KERNEL);
if (!necd)
return -ENOMEM;
dev_set_drvdata(&dssdev->dev, necd);
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = 255;
bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev,
&nec_8048_bl_ops, &props);
if (IS_ERR(bl)) {
r = PTR_ERR(bl);
kfree(necd);
return r;
}
necd->bl = bl;
bl->props.fb_blank = FB_BLANK_UNBLANK;
bl->props.power = FB_BLANK_UNBLANK;
bl->props.max_brightness = dssdev->max_backlight_level;
bl->props.brightness = dssdev->max_backlight_level;
r = nec_8048_bl_update_status(bl);
if (r < 0)
dev_err(&dssdev->dev, "failed to set lcd brightness\n");
return 0;
}
static void nec_8048_panel_remove(struct omap_dss_device *dssdev)
{
struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
struct backlight_device *bl = necd->bl;
bl->props.power = FB_BLANK_POWERDOWN;
nec_8048_bl_update_status(bl);
backlight_device_unregister(bl);
kfree(necd);
}
static int nec_8048_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
struct backlight_device *bl = necd->bl;
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
return r;
}
r = nec_8048_bl_update_status(bl);
if (r < 0)
dev_err(&dssdev->dev, "failed to set lcd brightness\n");
r = omapdss_dpi_display_enable(dssdev);
return r;
}
static void nec_8048_panel_disable(struct omap_dss_device *dssdev)
{
struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
struct backlight_device *bl = necd->bl;
omapdss_dpi_display_disable(dssdev);
bl->props.brightness = 0;
nec_8048_bl_update_status(bl);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
}
static int nec_8048_panel_suspend(struct omap_dss_device *dssdev)
{
nec_8048_panel_disable(dssdev);
return 0;
}
static int nec_8048_panel_resume(struct omap_dss_device *dssdev)
{
return nec_8048_panel_enable(dssdev);
}
static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev)
{
return 16;
}
static struct omap_dss_driver nec_8048_driver = {
.probe = nec_8048_panel_probe,
.remove = nec_8048_panel_remove,
.enable = nec_8048_panel_enable,
.disable = nec_8048_panel_disable,
.suspend = nec_8048_panel_suspend,
.resume = nec_8048_panel_resume,
.get_recommended_bpp = nec_8048_recommended_bpp,
.driver = {
.name = "NEC_8048_panel",
.owner = THIS_MODULE,
},
};
static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
unsigned char reg_data)
{
int ret = 0;
unsigned int cmd = 0, data = 0;
cmd = 0x0000 | reg_addr; /* register address write */
data = 0x0100 | reg_data ; /* register data write */
data = (cmd << 16) | data;
ret = spi_write(spi, (unsigned char *)&data, 4);
if (ret)
pr_err("error in spi_write %x\n", data);
return ret;
}
static int init_nec_8048_wvga_lcd(struct spi_device *spi)
{
unsigned int i;
/* Initialization Sequence */
/* nec_8048_spi_send(spi, REG, VAL) */
for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
nec_8048_init_seq[i].dat);
udelay(20);
nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
nec_8048_init_seq[i].dat);
return 0;
}
static int nec_8048_spi_probe(struct spi_device *spi)
{
spi->mode = SPI_MODE_0;
spi->bits_per_word = 32;
spi_setup(spi);
init_nec_8048_wvga_lcd(spi);
return omap_dss_register_driver(&nec_8048_driver);
}
static int nec_8048_spi_remove(struct spi_device *spi)
{
omap_dss_unregister_driver(&nec_8048_driver);
return 0;
}
static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg)
{
nec_8048_spi_send(spi, 2, 0x01);
mdelay(40);
return 0;
}
static int nec_8048_spi_resume(struct spi_device *spi)
{
/* reinitialize the panel */
spi_setup(spi);
nec_8048_spi_send(spi, 2, 0x00);
init_nec_8048_wvga_lcd(spi);
return 0;
}
static struct spi_driver nec_8048_spi_driver = {
.probe = nec_8048_spi_probe,
.remove = __devexit_p(nec_8048_spi_remove),
.suspend = nec_8048_spi_suspend,
.resume = nec_8048_spi_resume,
.driver = {
.name = "nec_8048_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
};
static int __init nec_8048_lcd_init(void)
{
return spi_register_driver(&nec_8048_spi_driver);
}
static void __exit nec_8048_lcd_exit(void)
{
return spi_unregister_driver(&nec_8048_spi_driver);
}
module_init(nec_8048_lcd_init);
module_exit(nec_8048_lcd_exit);
MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver");
MODULE_LICENSE("GPL");
/*
* LCD panel driver for Sharp LQ043T1DG01
*
* Copyright (C) 2009 Texas Instruments Inc
* Author: Vaibhav Hiremath <hvaibhav@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <plat/display.h>
static struct omap_video_timings sharp_lq_timings = {
.x_res = 480,
.y_res = 272,
.pixel_clock = 9000,
.hsw = 42,
.hfp = 3,
.hbp = 2,
.vsw = 11,
.vfp = 3,
.vbp = 2,
};
static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
goto err1;
}
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
{
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
/* wait at least 5 vsyncs after disabling the LCD */
msleep(100);
omapdss_dpi_display_disable(dssdev);
}
static int sharp_lq_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO;
dssdev->panel.acb = 0x0;
dssdev->panel.timings = sharp_lq_timings;
return 0;
}
static void sharp_lq_panel_remove(struct omap_dss_device *dssdev)
{
}
static int sharp_lq_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
r = sharp_lq_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void sharp_lq_panel_disable(struct omap_dss_device *dssdev)
{
sharp_lq_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev)
{
sharp_lq_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int sharp_lq_panel_resume(struct omap_dss_device *dssdev)
{
int r = 0;
r = sharp_lq_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static struct omap_dss_driver sharp_lq_driver = {
.probe = sharp_lq_panel_probe,
.remove = sharp_lq_panel_remove,
.enable = sharp_lq_panel_enable,
.disable = sharp_lq_panel_disable,
.suspend = sharp_lq_panel_suspend,
.resume = sharp_lq_panel_resume,
.driver = {
.name = "sharp_lq_panel",
.owner = THIS_MODULE,
},
};
static int __init sharp_lq_panel_drv_init(void)
{
return omap_dss_register_driver(&sharp_lq_driver);
}
static void __exit sharp_lq_panel_drv_exit(void)
{
omap_dss_unregister_driver(&sharp_lq_driver);
}
module_init(sharp_lq_panel_drv_init);
module_exit(sharp_lq_panel_drv_exit);
MODULE_LICENSE("GPL");
/*
* LCD panel driver for Toppoly TDO35S
*
* Copyright (C) 2009 CompuLab, Ltd.
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based on generic panel support
* Copyright (C) 2008 Nokia Corporation
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <plat/display.h>
static struct omap_video_timings toppoly_tdo_panel_timings = {
/* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
.x_res = 480,
.y_res = 640,
.pixel_clock = 26000,
.hfp = 104,
.hsw = 8,
.hbp = 8,
.vfp = 4,
.vsw = 2,
.vbp = 2,
};
static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
goto err1;
}
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
{
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
omapdss_dpi_display_disable(dssdev);
}
static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.config = OMAP_DSS_LCD_TFT |
OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS |
OMAP_DSS_LCD_IPC |
OMAP_DSS_LCD_ONOFF;
dssdev->panel.timings = toppoly_tdo_panel_timings;
return 0;
}
static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev)
{
}
static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev)
{
int r = 0;
r = toppoly_tdo_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev)
{
toppoly_tdo_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev)
{
toppoly_tdo_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
return 0;
}
static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev)
{
int r = 0;
r = toppoly_tdo_panel_power_on(dssdev);
if (r)
return r;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static struct omap_dss_driver generic_driver = {
.probe = toppoly_tdo_panel_probe,
.remove = toppoly_tdo_panel_remove,
.enable = toppoly_tdo_panel_enable,
.disable = toppoly_tdo_panel_disable,
.suspend = toppoly_tdo_panel_suspend,
.resume = toppoly_tdo_panel_resume,
.driver = {
.name = "toppoly_tdo35s_panel",
.owner = THIS_MODULE,
},
};
static int __init toppoly_tdo_panel_drv_init(void)
{
return omap_dss_register_driver(&generic_driver);
}
static void __exit toppoly_tdo_panel_drv_exit(void)
{
omap_dss_unregister_driver(&generic_driver);
}
module_init(toppoly_tdo_panel_drv_init);
module_exit(toppoly_tdo_panel_drv_exit);
MODULE_LICENSE("GPL");
......@@ -44,34 +44,40 @@
/* DISPC */
#define DISPC_BASE 0x48050400
#define DISPC_SZ_REGS SZ_1K
#define DISPC_SZ_REGS SZ_4K
struct dispc_reg { u16 idx; };
#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
/* DISPC common */
/*
* DISPC common registers and
* DISPC channel registers , ch = 0 for LCD, ch = 1 for
* DIGIT, and ch = 2 for LCD2
*/
#define DISPC_REVISION DISPC_REG(0x0000)
#define DISPC_SYSCONFIG DISPC_REG(0x0010)
#define DISPC_SYSSTATUS DISPC_REG(0x0014)
#define DISPC_IRQSTATUS DISPC_REG(0x0018)
#define DISPC_IRQENABLE DISPC_REG(0x001C)
#define DISPC_CONTROL DISPC_REG(0x0040)
#define DISPC_CONTROL2 DISPC_REG(0x0238)
#define DISPC_CONFIG DISPC_REG(0x0044)
#define DISPC_CONFIG2 DISPC_REG(0x0620)
#define DISPC_CAPABLE DISPC_REG(0x0048)
#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C)
#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050)
#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054)
#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058)
#define DISPC_DEFAULT_COLOR(ch) DISPC_REG(ch == 0 ? 0x004C : \
(ch == 1 ? 0x0050 : 0x03AC))
#define DISPC_TRANS_COLOR(ch) DISPC_REG(ch == 0 ? 0x0054 : \
(ch == 1 ? 0x0058 : 0x03B0))
#define DISPC_LINE_STATUS DISPC_REG(0x005C)
#define DISPC_LINE_NUMBER DISPC_REG(0x0060)
#define DISPC_TIMING_H DISPC_REG(0x0064)
#define DISPC_TIMING_V DISPC_REG(0x0068)
#define DISPC_POL_FREQ DISPC_REG(0x006C)
#define DISPC_DIVISOR DISPC_REG(0x0070)
#define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
#define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
#define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408)
#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
#define DISPC_SIZE_DIG DISPC_REG(0x0078)
#define DISPC_SIZE_LCD DISPC_REG(0x007C)
#define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
/* DISPC GFX plane */
#define DISPC_GFX_BA0 DISPC_REG(0x0080)
......@@ -86,13 +92,12 @@ struct dispc_reg { u16 idx; };
#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
#define DISPC_CPR_COEF_R DISPC_REG(0x0220)
#define DISPC_CPR_COEF_G DISPC_REG(0x0224)
#define DISPC_CPR_COEF_B DISPC_REG(0x0228)
#define DISPC_DATA_CYCLE1(ch) DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0)
#define DISPC_DATA_CYCLE2(ch) DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4)
#define DISPC_DATA_CYCLE3(ch) DISPC_REG(ch != 2 ? 0x01DC : 0x03C8)
#define DISPC_CPR_COEF_R(ch) DISPC_REG(ch != 2 ? 0x0220 : 0x03BC)
#define DISPC_CPR_COEF_G(ch) DISPC_REG(ch != 2 ? 0x0224 : 0x03B8)
#define DISPC_CPR_COEF_B(ch) DISPC_REG(ch != 2 ? 0x0228 : 0x03B4)
#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
......@@ -217,18 +222,29 @@ void dispc_save_context(void)
SR(IRQENABLE);
SR(CONTROL);
SR(CONFIG);
SR(DEFAULT_COLOR0);
SR(DEFAULT_COLOR1);
SR(TRANS_COLOR0);
SR(TRANS_COLOR1);
SR(DEFAULT_COLOR(0));
SR(DEFAULT_COLOR(1));
SR(TRANS_COLOR(0));
SR(TRANS_COLOR(1));
SR(LINE_NUMBER);
SR(TIMING_H);
SR(TIMING_V);
SR(POL_FREQ);
SR(DIVISOR);
SR(TIMING_H(0));
SR(TIMING_V(0));
SR(POL_FREQ(0));
SR(DIVISOR(0));
SR(GLOBAL_ALPHA);
SR(SIZE_DIG);
SR(SIZE_LCD);
SR(SIZE_LCD(0));
if (dss_has_feature(FEAT_MGR_LCD2)) {
SR(CONTROL2);
SR(DEFAULT_COLOR(2));
SR(TRANS_COLOR(2));
SR(SIZE_LCD(2));
SR(TIMING_H(2));
SR(TIMING_V(2));
SR(POL_FREQ(2));
SR(DIVISOR(2));
SR(CONFIG2);
}
SR(GFX_BA0);
SR(GFX_BA1);
......@@ -241,13 +257,22 @@ void dispc_save_context(void)
SR(GFX_WINDOW_SKIP);
SR(GFX_TABLE_BA);
SR(DATA_CYCLE1);
SR(DATA_CYCLE2);
SR(DATA_CYCLE3);
SR(CPR_COEF_R);
SR(CPR_COEF_G);
SR(CPR_COEF_B);
SR(DATA_CYCLE1(0));
SR(DATA_CYCLE2(0));
SR(DATA_CYCLE3(0));
SR(CPR_COEF_R(0));
SR(CPR_COEF_G(0));
SR(CPR_COEF_B(0));
if (dss_has_feature(FEAT_MGR_LCD2)) {
SR(CPR_COEF_B(2));
SR(CPR_COEF_G(2));
SR(CPR_COEF_R(2));
SR(DATA_CYCLE1(2));
SR(DATA_CYCLE2(2));
SR(DATA_CYCLE3(2));
}
SR(GFX_PRELOAD);
......@@ -356,18 +381,28 @@ void dispc_restore_context(void)
/*RR(IRQENABLE);*/
/*RR(CONTROL);*/
RR(CONFIG);
RR(DEFAULT_COLOR0);
RR(DEFAULT_COLOR1);
RR(TRANS_COLOR0);
RR(TRANS_COLOR1);
RR(DEFAULT_COLOR(0));
RR(DEFAULT_COLOR(1));
RR(TRANS_COLOR(0));
RR(TRANS_COLOR(1));
RR(LINE_NUMBER);
RR(TIMING_H);
RR(TIMING_V);
RR(POL_FREQ);
RR(DIVISOR);
RR(TIMING_H(0));
RR(TIMING_V(0));
RR(POL_FREQ(0));
RR(DIVISOR(0));
RR(GLOBAL_ALPHA);
RR(SIZE_DIG);
RR(SIZE_LCD);
RR(SIZE_LCD(0));
if (dss_has_feature(FEAT_MGR_LCD2)) {
RR(DEFAULT_COLOR(2));
RR(TRANS_COLOR(2));
RR(SIZE_LCD(2));
RR(TIMING_H(2));
RR(TIMING_V(2));
RR(POL_FREQ(2));
RR(DIVISOR(2));
RR(CONFIG2);
}
RR(GFX_BA0);
RR(GFX_BA1);
......@@ -380,13 +415,22 @@ void dispc_restore_context(void)
RR(GFX_WINDOW_SKIP);
RR(GFX_TABLE_BA);
RR(DATA_CYCLE1);
RR(DATA_CYCLE2);
RR(DATA_CYCLE3);
RR(CPR_COEF_R);
RR(CPR_COEF_G);
RR(CPR_COEF_B);
RR(DATA_CYCLE1(0));
RR(DATA_CYCLE2(0));
RR(DATA_CYCLE3(0));
RR(CPR_COEF_R(0));
RR(CPR_COEF_G(0));
RR(CPR_COEF_B(0));
if (dss_has_feature(FEAT_MGR_LCD2)) {
RR(DATA_CYCLE1(2));
RR(DATA_CYCLE2(2));
RR(DATA_CYCLE3(2));
RR(CPR_COEF_B(2));
RR(CPR_COEF_G(2));
RR(CPR_COEF_R(2));
}
RR(GFX_PRELOAD);
......@@ -490,7 +534,8 @@ void dispc_restore_context(void)
/* enable last, because LCD & DIGIT enable are here */
RR(CONTROL);
if (dss_has_feature(FEAT_MGR_LCD2))
RR(CONTROL2);
/* clear spurious SYNC_LOST_DIGIT interrupts */
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
......@@ -516,42 +561,63 @@ bool dispc_go_busy(enum omap_channel channel)
{
int bit;
if (channel == OMAP_DSS_CHANNEL_LCD)
if (channel == OMAP_DSS_CHANNEL_LCD ||
channel == OMAP_DSS_CHANNEL_LCD2)
bit = 5; /* GOLCD */
else
bit = 6; /* GODIGIT */
return REG_GET(DISPC_CONTROL, bit, bit) == 1;
if (channel == OMAP_DSS_CHANNEL_LCD2)
return REG_GET(DISPC_CONTROL2, bit, bit) == 1;
else
return REG_GET(DISPC_CONTROL, bit, bit) == 1;
}
void dispc_go(enum omap_channel channel)
{
int bit;
bool enable_bit, go_bit;
enable_clocks(1);
if (channel == OMAP_DSS_CHANNEL_LCD)
if (channel == OMAP_DSS_CHANNEL_LCD ||
channel == OMAP_DSS_CHANNEL_LCD2)
bit = 0; /* LCDENABLE */
else
bit = 1; /* DIGITALENABLE */
/* if the channel is not enabled, we don't need GO */
if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
if (channel == OMAP_DSS_CHANNEL_LCD2)
enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
else
enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
if (!enable_bit)
goto end;
if (channel == OMAP_DSS_CHANNEL_LCD)
if (channel == OMAP_DSS_CHANNEL_LCD ||
channel == OMAP_DSS_CHANNEL_LCD2)
bit = 5; /* GOLCD */
else
bit = 6; /* GODIGIT */
if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
if (channel == OMAP_DSS_CHANNEL_LCD2)
go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
else
go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
if (go_bit) {
DSSERR("GO bit not down for channel %d\n", channel);
goto end;
}
DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
(channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT"));
REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
else
REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
end:
enable_clocks(0);
}
......@@ -773,13 +839,26 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
dispc_write_reg(vsi_reg[plane-1], val);
}
static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
{
if (!dss_has_feature(FEAT_PRE_MULT_ALPHA))
return;
if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
plane == OMAP_DSS_VIDEO1)
return;
REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28);
}
static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
{
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return;
BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
plane == OMAP_DSS_VIDEO1);
if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
plane == OMAP_DSS_VIDEO1)
return;
if (plane == OMAP_DSS_GFX)
REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
......@@ -851,6 +930,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
{
int shift;
u32 val;
int chan = 0, chan2 = 0;
switch (plane) {
case OMAP_DSS_GFX:
......@@ -866,7 +946,29 @@ static void _dispc_set_channel_out(enum omap_plane plane,
}
val = dispc_read_reg(dispc_reg_att[plane]);
val = FLD_MOD(val, channel, shift, shift);
if (dss_has_feature(FEAT_MGR_LCD2)) {
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
chan = 0;
chan2 = 0;
break;
case OMAP_DSS_CHANNEL_DIGIT:
chan = 1;
chan2 = 0;
break;
case OMAP_DSS_CHANNEL_LCD2:
chan = 0;
chan2 = 1;
break;
default:
BUG();
}
val = FLD_MOD(val, chan, shift, shift);
val = FLD_MOD(val, chan2, 31, 30);
} else {
val = FLD_MOD(val, channel, shift, shift);
}
dispc_write_reg(dispc_reg_att[plane], val);
}
......@@ -923,13 +1025,13 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
enable_clocks(0);
}
void dispc_set_lcd_size(u16 width, u16 height)
void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
{
u32 val;
BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
enable_clocks(1);
dispc_write_reg(DISPC_SIZE_LCD, val);
dispc_write_reg(DISPC_SIZE_LCD(channel), val);
enable_clocks(0);
}
......@@ -1426,12 +1528,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror,
}
}
static unsigned long calc_fclk_five_taps(u16 width, u16 height,
u16 out_width, u16 out_height, enum omap_color_mode color_mode)
static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode)
{
u32 fclk = 0;
/* FIXME venc pclk? */
u64 tmp, pclk = dispc_pclk_rate();
u64 tmp, pclk = dispc_pclk_rate(channel);
if (height > out_height) {
/* FIXME get real display PPL */
......@@ -1463,8 +1566,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height,
return fclk;
}
static unsigned long calc_fclk(u16 width, u16 height,
u16 out_width, u16 out_height)
static unsigned long calc_fclk(enum omap_channel channel, u16 width,
u16 height, u16 out_width, u16 out_height)
{
unsigned int hf, vf;
......@@ -1488,7 +1591,7 @@ static unsigned long calc_fclk(u16 width, u16 height,
vf = 1;
/* FIXME venc pclk? */
return dispc_pclk_rate() * vf * hf;
return dispc_pclk_rate(channel) * vf * hf;
}
void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
......@@ -1507,7 +1610,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, int mirror,
u8 global_alpha)
u8 global_alpha, u8 pre_mult_alpha,
enum omap_channel channel)
{
const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
bool five_taps = 0;
......@@ -1536,29 +1640,12 @@ static int _dispc_setup_plane(enum omap_plane plane,
height, pos_y, out_height);
}
if (!dss_feat_color_mode_supported(plane, color_mode))
return -EINVAL;
if (plane == OMAP_DSS_GFX) {
if (width != out_width || height != out_height)
return -EINVAL;
switch (color_mode) {
case OMAP_DSS_COLOR_ARGB16:
case OMAP_DSS_COLOR_ARGB32:
case OMAP_DSS_COLOR_RGBA32:
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return -EINVAL;
case OMAP_DSS_COLOR_RGBX32:
if (cpu_is_omap24xx())
return -EINVAL;
/* fall through */
case OMAP_DSS_COLOR_RGB12U:
case OMAP_DSS_COLOR_RGB16:
case OMAP_DSS_COLOR_RGB24P:
case OMAP_DSS_COLOR_RGB24U:
break;
default:
return -EINVAL;
}
} else {
/* video plane */
......@@ -1572,42 +1659,16 @@ static int _dispc_setup_plane(enum omap_plane plane,
out_height > height * 8)
return -EINVAL;
switch (color_mode) {
case OMAP_DSS_COLOR_RGBX32:
case OMAP_DSS_COLOR_RGB12U:
if (cpu_is_omap24xx())
return -EINVAL;
/* fall through */
case OMAP_DSS_COLOR_RGB16:
case OMAP_DSS_COLOR_RGB24P:
case OMAP_DSS_COLOR_RGB24U:
break;
case OMAP_DSS_COLOR_ARGB16:
case OMAP_DSS_COLOR_ARGB32:
case OMAP_DSS_COLOR_RGBA32:
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return -EINVAL;
if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
plane == OMAP_DSS_VIDEO1)
return -EINVAL;
break;
case OMAP_DSS_COLOR_YUV2:
case OMAP_DSS_COLOR_UYVY:
if (color_mode == OMAP_DSS_COLOR_YUV2 ||
color_mode == OMAP_DSS_COLOR_UYVY)
cconv = 1;
break;
default:
return -EINVAL;
}
/* Must use 5-tap filter? */
five_taps = height > out_height * 2;
if (!five_taps) {
fclk = calc_fclk(width, height,
out_width, out_height);
fclk = calc_fclk(channel, width, height, out_width,
out_height);
/* Try 5-tap filter if 3-tap fclk is too high */
if (cpu_is_omap34xx() && height > out_height &&
......@@ -1621,7 +1682,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
}
if (five_taps)
fclk = calc_fclk_five_taps(width, height,
fclk = calc_fclk_five_taps(channel, width, height,
out_width, out_height, color_mode);
DSSDBG("required fclk rate = %lu Hz\n", fclk);
......@@ -1693,8 +1754,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
_dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
if (plane != OMAP_DSS_VIDEO1)
_dispc_setup_global_alpha(plane, global_alpha);
_dispc_set_pre_mult_alpha(plane, pre_mult_alpha);
_dispc_setup_global_alpha(plane, global_alpha);
return 0;
}
......@@ -1710,36 +1771,44 @@ static void dispc_disable_isr(void *data, u32 mask)
complete(compl);
}
static void _enable_lcd_out(bool enable)
static void _enable_lcd_out(enum omap_channel channel, bool enable)
{
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
else
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
}
static void dispc_enable_lcd_out(bool enable)
static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
{
struct completion frame_done_completion;
bool is_on;
int r;
u32 irq;
enable_clocks(1);
/* When we disable LCD output, we need to wait until frame is done.
* Otherwise the DSS is still working, and turning off the clocks
* prevents DSS from going to OFF mode */
is_on = REG_GET(DISPC_CONTROL, 0, 0);
is_on = channel == OMAP_DSS_CHANNEL_LCD2 ?
REG_GET(DISPC_CONTROL2, 0, 0) :
REG_GET(DISPC_CONTROL, 0, 0);
irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 :
DISPC_IRQ_FRAMEDONE;
if (!enable && is_on) {
init_completion(&frame_done_completion);
r = omap_dispc_register_isr(dispc_disable_isr,
&frame_done_completion,
DISPC_IRQ_FRAMEDONE);
&frame_done_completion, irq);
if (r)
DSSERR("failed to register FRAMEDONE isr\n");
}
_enable_lcd_out(enable);
_enable_lcd_out(channel, enable);
if (!enable && is_on) {
if (!wait_for_completion_timeout(&frame_done_completion,
......@@ -1747,8 +1816,7 @@ static void dispc_enable_lcd_out(bool enable)
DSSERR("timeout waiting for FRAME DONE\n");
r = omap_dispc_unregister_isr(dispc_disable_isr,
&frame_done_completion,
DISPC_IRQ_FRAMEDONE);
&frame_done_completion, irq);
if (r)
DSSERR("failed to unregister FRAMEDONE isr\n");
......@@ -1818,6 +1886,8 @@ static void dispc_enable_digit_out(bool enable)
unsigned long flags;
spin_lock_irqsave(&dispc.irq_lock, flags);
dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
if (dss_has_feature(FEAT_MGR_LCD2))
dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
_omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc.irq_lock, flags);
......@@ -1832,14 +1902,17 @@ bool dispc_is_channel_enabled(enum omap_channel channel)
return !!REG_GET(DISPC_CONTROL, 0, 0);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
return !!REG_GET(DISPC_CONTROL, 1, 1);
else if (channel == OMAP_DSS_CHANNEL_LCD2)
return !!REG_GET(DISPC_CONTROL2, 0, 0);
else
BUG();
}
void dispc_enable_channel(enum omap_channel channel, bool enable)
{
if (channel == OMAP_DSS_CHANNEL_LCD)
dispc_enable_lcd_out(enable);
if (channel == OMAP_DSS_CHANNEL_LCD ||
channel == OMAP_DSS_CHANNEL_LCD2)
dispc_enable_lcd_out(channel, enable);
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
dispc_enable_digit_out(enable);
else
......@@ -1848,6 +1921,9 @@ void dispc_enable_channel(enum omap_channel channel, bool enable)
void dispc_lcd_enable_signal_polarity(bool act_high)
{
if (!dss_has_feature(FEAT_LCDENABLEPOL))
return;
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
enable_clocks(0);
......@@ -1855,6 +1931,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high)
void dispc_lcd_enable_signal(bool enable)
{
if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
return;
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
enable_clocks(0);
......@@ -1862,20 +1941,27 @@ void dispc_lcd_enable_signal(bool enable)
void dispc_pck_free_enable(bool enable)
{
if (!dss_has_feature(FEAT_PCKFREEENABLE))
return;
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
enable_clocks(0);
}
void dispc_enable_fifohandcheck(bool enable)
void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
{
enable_clocks(1);
REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
else
REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
enable_clocks(0);
}
void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
void dispc_set_lcd_display_type(enum omap_channel channel,
enum omap_lcd_display_type type)
{
int mode;
......@@ -1894,7 +1980,10 @@ void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
}
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
else
REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
enable_clocks(0);
}
......@@ -1908,25 +1997,21 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode)
void dispc_set_default_color(enum omap_channel channel, u32 color)
{
const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
DISPC_DEFAULT_COLOR1 };
enable_clocks(1);
dispc_write_reg(def_reg[channel], color);
dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
enable_clocks(0);
}
u32 dispc_get_default_color(enum omap_channel channel)
{
const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
DISPC_DEFAULT_COLOR1 };
u32 l;
BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
channel != OMAP_DSS_CHANNEL_LCD);
channel != OMAP_DSS_CHANNEL_LCD &&
channel != OMAP_DSS_CHANNEL_LCD2);
enable_clocks(1);
l = dispc_read_reg(def_reg[channel]);
l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
enable_clocks(0);
return l;
......@@ -1936,16 +2021,15 @@ void dispc_set_trans_key(enum omap_channel ch,
enum omap_dss_trans_key_type type,
u32 trans_key)
{
const struct dispc_reg tr_reg[] = {
DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
else /* OMAP_DSS_CHANNEL_DIGIT */
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
dispc_write_reg(tr_reg[ch], trans_key);
dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
enable_clocks(0);
}
......@@ -1953,21 +2037,20 @@ void dispc_get_trans_key(enum omap_channel ch,
enum omap_dss_trans_key_type *type,
u32 *trans_key)
{
const struct dispc_reg tr_reg[] = {
DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
enable_clocks(1);
if (type) {
if (ch == OMAP_DSS_CHANNEL_LCD)
*type = REG_GET(DISPC_CONFIG, 11, 11);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
*type = REG_GET(DISPC_CONFIG, 13, 13);
else if (ch == OMAP_DSS_CHANNEL_LCD2)
*type = REG_GET(DISPC_CONFIG2, 11, 11);
else
BUG();
}
if (trans_key)
*trans_key = dispc_read_reg(tr_reg[ch]);
*trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
enable_clocks(0);
}
......@@ -1976,8 +2059,10 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable)
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
else /* OMAP_DSS_CHANNEL_DIGIT */
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
enable_clocks(0);
}
void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
......@@ -1988,8 +2073,10 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
else /* OMAP_DSS_CHANNEL_DIGIT */
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
enable_clocks(0);
}
bool dispc_alpha_blending_enabled(enum omap_channel ch)
......@@ -2003,13 +2090,14 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
if (ch == OMAP_DSS_CHANNEL_LCD)
enabled = REG_GET(DISPC_CONFIG, 18, 18);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
enabled = REG_GET(DISPC_CONFIG, 18, 18);
enabled = REG_GET(DISPC_CONFIG, 19, 19);
else if (ch == OMAP_DSS_CHANNEL_LCD2)
enabled = REG_GET(DISPC_CONFIG2, 18, 18);
else
BUG();
enable_clocks(0);
return enabled;
}
......@@ -2022,6 +2110,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
enabled = REG_GET(DISPC_CONFIG, 10, 10);
else if (ch == OMAP_DSS_CHANNEL_DIGIT)
enabled = REG_GET(DISPC_CONFIG, 12, 12);
else if (ch == OMAP_DSS_CHANNEL_LCD2)
enabled = REG_GET(DISPC_CONFIG2, 10, 10);
else
BUG();
enable_clocks(0);
......@@ -2030,7 +2120,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
}
void dispc_set_tft_data_lines(u8 data_lines)
void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
{
int code;
......@@ -2053,11 +2143,15 @@ void dispc_set_tft_data_lines(u8 data_lines)
}
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
else
REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
enable_clocks(0);
}
void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
void dispc_set_parallel_interface_mode(enum omap_channel channel,
enum omap_parallel_interface_mode mode)
{
u32 l;
int stallmode;
......@@ -2087,13 +2181,17 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
enable_clocks(1);
l = dispc_read_reg(DISPC_CONTROL);
l = FLD_MOD(l, stallmode, 11, 11);
l = FLD_MOD(l, gpout0, 15, 15);
l = FLD_MOD(l, gpout1, 16, 16);
dispc_write_reg(DISPC_CONTROL, l);
if (channel == OMAP_DSS_CHANNEL_LCD2) {
l = dispc_read_reg(DISPC_CONTROL2);
l = FLD_MOD(l, stallmode, 11, 11);
dispc_write_reg(DISPC_CONTROL2, l);
} else {
l = dispc_read_reg(DISPC_CONTROL);
l = FLD_MOD(l, stallmode, 11, 11);
l = FLD_MOD(l, gpout0, 15, 15);
l = FLD_MOD(l, gpout1, 16, 16);
dispc_write_reg(DISPC_CONTROL, l);
}
enable_clocks(0);
}
......@@ -2129,8 +2227,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
timings->vfp, timings->vbp);
}
static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
int vsw, int vfp, int vbp)
static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
int hfp, int hbp, int vsw, int vfp, int vbp)
{
u32 timing_h, timing_v;
......@@ -2149,13 +2247,14 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
}
enable_clocks(1);
dispc_write_reg(DISPC_TIMING_H, timing_h);
dispc_write_reg(DISPC_TIMING_V, timing_v);
dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
enable_clocks(0);
}
/* change name to mode? */
void dispc_set_lcd_timings(struct omap_video_timings *timings)
void dispc_set_lcd_timings(enum omap_channel channel,
struct omap_video_timings *timings)
{
unsigned xtot, ytot;
unsigned long ht, vt;
......@@ -2165,10 +2264,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
timings->vfp, timings->vbp))
BUG();
_dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
timings->vsw, timings->vfp, timings->vbp);
_dispc_set_lcd_timings(channel, timings->hsw, timings->hfp,
timings->hbp, timings->vsw, timings->vfp,
timings->vbp);
dispc_set_lcd_size(timings->x_res, timings->y_res);
dispc_set_lcd_size(channel, timings->x_res, timings->y_res);
xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
......@@ -2176,7 +2276,8 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
ht = (timings->pixel_clock * 1000) / xtot;
vt = (timings->pixel_clock * 1000) / xtot / ytot;
DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res,
timings->y_res);
DSSDBG("pck %u\n", timings->pixel_clock);
DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
timings->hsw, timings->hfp, timings->hbp,
......@@ -2185,21 +2286,23 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings)
DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
}
static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
u16 pck_div)
{
BUG_ON(lck_div < 1);
BUG_ON(pck_div < 2);
enable_clocks(1);
dispc_write_reg(DISPC_DIVISOR,
dispc_write_reg(DISPC_DIVISOR(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
enable_clocks(0);
}
static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
int *pck_div)
{
u32 l;
l = dispc_read_reg(DISPC_DIVISOR);
l = dispc_read_reg(DISPC_DIVISOR(channel));
*lck_div = FLD_GET(l, 23, 16);
*pck_div = FLD_GET(l, 7, 0);
}
......@@ -2219,13 +2322,13 @@ unsigned long dispc_fclk_rate(void)
return r;
}
unsigned long dispc_lclk_rate(void)
unsigned long dispc_lclk_rate(enum omap_channel channel)
{
int lcd;
unsigned long r;
u32 l;
l = dispc_read_reg(DISPC_DIVISOR);
l = dispc_read_reg(DISPC_DIVISOR(channel));
lcd = FLD_GET(l, 23, 16);
......@@ -2234,13 +2337,13 @@ unsigned long dispc_lclk_rate(void)
return r / lcd;
}
unsigned long dispc_pclk_rate(void)
unsigned long dispc_pclk_rate(enum omap_channel channel)
{
int lcd, pcd;
unsigned long r;
u32 l;
l = dispc_read_reg(DISPC_DIVISOR);
l = dispc_read_reg(DISPC_DIVISOR(channel));
lcd = FLD_GET(l, 23, 16);
pcd = FLD_GET(l, 7, 0);
......@@ -2256,8 +2359,6 @@ void dispc_dump_clocks(struct seq_file *s)
enable_clocks(1);
dispc_get_lcd_divisor(&lcd, &pcd);
seq_printf(s, "- DISPC -\n");
seq_printf(s, "dispc fclk source = %s\n",
......@@ -2265,9 +2366,25 @@ void dispc_dump_clocks(struct seq_file *s)
"dss1_alwon_fclk" : "dsi1_pll_fclk");
seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
seq_printf(s, "- LCD1 -\n");
dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
if (dss_has_feature(FEAT_MGR_LCD2)) {
seq_printf(s, "- LCD2 -\n");
dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
}
enable_clocks(0);
}
......@@ -2309,6 +2426,12 @@ void dispc_dump_irqs(struct seq_file *s)
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
PIS(WAKEUP);
if (dss_has_feature(FEAT_MGR_LCD2)) {
PIS(FRAMEDONE2);
PIS(VSYNC2);
PIS(ACBIAS_COUNT_STAT2);
PIS(SYNC_LOST2);
}
#undef PIS
}
#endif
......@@ -2327,19 +2450,30 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_CONTROL);
DUMPREG(DISPC_CONFIG);
DUMPREG(DISPC_CAPABLE);
DUMPREG(DISPC_DEFAULT_COLOR0);
DUMPREG(DISPC_DEFAULT_COLOR1);
DUMPREG(DISPC_TRANS_COLOR0);
DUMPREG(DISPC_TRANS_COLOR1);
DUMPREG(DISPC_DEFAULT_COLOR(0));
DUMPREG(DISPC_DEFAULT_COLOR(1));
DUMPREG(DISPC_TRANS_COLOR(0));
DUMPREG(DISPC_TRANS_COLOR(1));
DUMPREG(DISPC_LINE_STATUS);
DUMPREG(DISPC_LINE_NUMBER);
DUMPREG(DISPC_TIMING_H);
DUMPREG(DISPC_TIMING_V);
DUMPREG(DISPC_POL_FREQ);
DUMPREG(DISPC_DIVISOR);
DUMPREG(DISPC_TIMING_H(0));
DUMPREG(DISPC_TIMING_V(0));
DUMPREG(DISPC_POL_FREQ(0));
DUMPREG(DISPC_DIVISOR(0));
DUMPREG(DISPC_GLOBAL_ALPHA);
DUMPREG(DISPC_SIZE_DIG);
DUMPREG(DISPC_SIZE_LCD);
DUMPREG(DISPC_SIZE_LCD(0));
if (dss_has_feature(FEAT_MGR_LCD2)) {
DUMPREG(DISPC_CONTROL2);
DUMPREG(DISPC_CONFIG2);
DUMPREG(DISPC_DEFAULT_COLOR(2));
DUMPREG(DISPC_TRANS_COLOR(2));
DUMPREG(DISPC_TIMING_H(2));
DUMPREG(DISPC_TIMING_V(2));
DUMPREG(DISPC_POL_FREQ(2));
DUMPREG(DISPC_DIVISOR(2));
DUMPREG(DISPC_SIZE_LCD(2));
}
DUMPREG(DISPC_GFX_BA0);
DUMPREG(DISPC_GFX_BA1);
......@@ -2353,13 +2487,22 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_GFX_WINDOW_SKIP);
DUMPREG(DISPC_GFX_TABLE_BA);
DUMPREG(DISPC_DATA_CYCLE1);
DUMPREG(DISPC_DATA_CYCLE2);
DUMPREG(DISPC_DATA_CYCLE3);
DUMPREG(DISPC_CPR_COEF_R);
DUMPREG(DISPC_CPR_COEF_G);
DUMPREG(DISPC_CPR_COEF_B);
DUMPREG(DISPC_DATA_CYCLE1(0));
DUMPREG(DISPC_DATA_CYCLE2(0));
DUMPREG(DISPC_DATA_CYCLE3(0));
DUMPREG(DISPC_CPR_COEF_R(0));
DUMPREG(DISPC_CPR_COEF_G(0));
DUMPREG(DISPC_CPR_COEF_B(0));
if (dss_has_feature(FEAT_MGR_LCD2)) {
DUMPREG(DISPC_DATA_CYCLE1(2));
DUMPREG(DISPC_DATA_CYCLE2(2));
DUMPREG(DISPC_DATA_CYCLE3(2));
DUMPREG(DISPC_CPR_COEF_R(2));
DUMPREG(DISPC_CPR_COEF_G(2));
DUMPREG(DISPC_CPR_COEF_B(2));
}
DUMPREG(DISPC_GFX_PRELOAD);
......@@ -2458,8 +2601,8 @@ void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
bool ihs, bool ivs, u8 acbi, u8 acb)
static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb)
{
u32 l = 0;
......@@ -2476,13 +2619,14 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
l |= FLD_VAL(acb, 7, 0);
enable_clocks(1);
dispc_write_reg(DISPC_POL_FREQ, l);
dispc_write_reg(DISPC_POL_FREQ(channel), l);
enable_clocks(0);
}
void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
void dispc_set_pol_freq(enum omap_channel channel,
enum omap_panel_config config, u8 acbi, u8 acb)
{
_dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
_dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0,
(config & OMAP_DSS_LCD_RF) != 0,
(config & OMAP_DSS_LCD_IEO) != 0,
(config & OMAP_DSS_LCD_IPC) != 0,
......@@ -2551,24 +2695,26 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
return 0;
}
int dispc_set_clock_div(struct dispc_clock_info *cinfo)
int dispc_set_clock_div(enum omap_channel channel,
struct dispc_clock_info *cinfo)
{
DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
return 0;
}
int dispc_get_clock_div(struct dispc_clock_info *cinfo)
int dispc_get_clock_div(enum omap_channel channel,
struct dispc_clock_info *cinfo)
{
unsigned long fck;
fck = dispc_fclk_rate();
cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16);
cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0);
cinfo->lck = fck / cinfo->lck_div;
cinfo->pck = cinfo->lck / cinfo->pck_div;
......@@ -2708,6 +2854,8 @@ static void print_irq_status(u32 status)
PIS(VID2_FIFO_UNDERFLOW);
PIS(SYNC_LOST);
PIS(SYNC_LOST_DIGIT);
if (dss_has_feature(FEAT_MGR_LCD2))
PIS(SYNC_LOST2);
#undef PIS
printk("\n");
......@@ -2926,6 +3074,45 @@ static void dispc_error_worker(struct work_struct *work)
}
}
if (errors & DISPC_IRQ_SYNC_LOST2) {
struct omap_overlay_manager *manager = NULL;
bool enable = false;
DSSERR("SYNC_LOST for LCD2, disabling LCD2\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
struct omap_overlay_manager *mgr;
mgr = omap_dss_get_overlay_manager(i);
if (mgr->id == OMAP_DSS_CHANNEL_LCD2) {
manager = mgr;
enable = mgr->device->state ==
OMAP_DSS_DISPLAY_ACTIVE;
mgr->device->driver->disable(mgr->device);
break;
}
}
if (manager) {
struct omap_dss_device *dssdev = manager->device;
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
continue;
if (ovl->id != 0 && ovl->manager == manager)
dispc_enable_plane(ovl->id, 0);
}
dispc_go(manager->id);
mdelay(50);
if (enable)
dssdev->driver->enable(dssdev);
}
}
if (errors & DISPC_IRQ_OCP_ERR) {
DSSERR("OCP_ERR\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
......@@ -3033,6 +3220,8 @@ static void _omap_dispc_initialize_irq(void)
memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
if (dss_has_feature(FEAT_MGR_LCD2))
dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
/* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
* so clear it */
......@@ -3065,7 +3254,8 @@ static void _omap_dispc_initial_config(void)
dispc_write_reg(DISPC_SYSCONFIG, l);
/* FUNCGATED */
REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
if (dss_has_feature(FEAT_FUNCGATED))
REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
/* L3 firewall setting: enable access to OCM RAM */
/* XXX this should be somewhere in plat-omap */
......@@ -3139,17 +3329,18 @@ int dispc_setup_plane(enum omap_plane plane,
enum omap_color_mode color_mode,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror, u8 global_alpha)
u8 rotation, bool mirror, u8 global_alpha,
u8 pre_mult_alpha, enum omap_channel channel)
{
int r = 0;
DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
"%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
"%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
plane, paddr, screen_width, pos_x, pos_y,
width, height,
out_width, out_height,
ilace, color_mode,
rotation, mirror);
rotation, mirror, channel);
enable_clocks(1);
......@@ -3161,7 +3352,8 @@ int dispc_setup_plane(enum omap_plane plane,
color_mode, ilace,
rotation_type,
rotation, mirror,
global_alpha);
global_alpha,
pre_mult_alpha, channel);
enable_clocks(0);
......
......@@ -40,8 +40,9 @@ static struct {
} dpi;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
struct dsi_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo;
......@@ -58,7 +59,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
r = dispc_set_clock_div(&dispc_cinfo);
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
return r;
......@@ -69,8 +70,9 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
return 0;
}
#else
static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
unsigned long *fck, int *lck_div, int *pck_div)
static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
......@@ -84,7 +86,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
if (r)
return r;
r = dispc_set_clock_div(&dispc_cinfo);
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
return r;
......@@ -107,17 +109,17 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
dssdev->panel.acb);
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
dssdev->panel.acbi, dssdev->panel.acb);
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div);
r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
&lck_div, &pck_div);
#else
r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div);
r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
&lck_div, &pck_div);
#endif
if (r)
goto err0;
......@@ -132,7 +134,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
t->pixel_clock = pck;
}
dispc_set_lcd_timings(t);
dispc_set_lcd_timings(dssdev->manager->id, t);
err0:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
......@@ -145,10 +147,12 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
OMAP_DSS_LCD_DISPLAY_STN);
dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
dispc_set_parallel_interface_mode(dssdev->manager->id,
OMAP_DSS_PARALLELMODE_BYPASS);
dispc_set_lcd_display_type(dssdev->manager->id, is_tft ?
OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
dispc_set_tft_data_lines(dssdev->manager->id,
dssdev->phy.dpi.data_lines);
return 0;
}
......@@ -234,7 +238,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev,
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
dpi_set_mode(dssdev);
dispc_go(OMAP_DSS_CHANNEL_LCD);
dispc_go(dssdev->manager->id);
}
}
EXPORT_SYMBOL(dpi_set_timings);
......
......@@ -792,7 +792,8 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
}
/* calculate clock rates using dividers in cinfo */
static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
struct dsi_clock_info *cinfo)
{
if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
return -EINVAL;
......@@ -812,7 +813,7 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
* with DSS2_FCK source also */
cinfo->highfreq = 0;
} else {
cinfo->clkin = dispc_pclk_rate();
cinfo->clkin = dispc_pclk_rate(dssdev->manager->id);
if (cinfo->clkin < 32000000)
cinfo->highfreq = 0;
......@@ -1206,8 +1207,8 @@ void dsi_dump_clocks(struct seq_file *s)
seq_printf(s, "VP_CLK\t\t%lu\n"
"VP_PCLK\t\t%lu\n",
dispc_lclk_rate(),
dispc_pclk_rate());
dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
enable_clocks(0);
}
......@@ -2888,7 +2889,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h,
enlarge_update_area);
dispc_set_lcd_size(*w, *h);
dispc_set_lcd_size(dssdev->manager->id, *w, *h);
}
return 0;
......@@ -2947,12 +2948,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
return r;
}
dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
dispc_set_lcd_display_type(dssdev->manager->id,
OMAP_DSS_LCD_DISPLAY_TFT);
dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
dispc_enable_fifohandcheck(1);
dispc_set_parallel_interface_mode(dssdev->manager->id,
OMAP_DSS_PARALLELMODE_DSI);
dispc_enable_fifohandcheck(dssdev->manager->id, 1);
dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
{
struct omap_video_timings timings = {
......@@ -2964,7 +2967,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
.vbp = 0,
};
dispc_set_lcd_timings(&timings);
dispc_set_lcd_timings(dssdev->manager->id, &timings);
}
return 0;
......@@ -2987,7 +2990,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
cinfo.regm = dssdev->phy.dsi.div.regm;
cinfo.regm3 = dssdev->phy.dsi.div.regm3;
cinfo.regm4 = dssdev->phy.dsi.div.regm4;
r = dsi_calc_clock_rates(&cinfo);
r = dsi_calc_clock_rates(dssdev, &cinfo);
if (r) {
DSSERR("Failed to calc dsi clocks\n");
return r;
......@@ -3019,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
return r;
}
r = dispc_set_clock_div(&dispc_cinfo);
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r) {
DSSERR("Failed to set dispc clocks\n");
return r;
......
......@@ -333,9 +333,9 @@ void dispc_disable_sidle(void);
void dispc_lcd_enable_signal_polarity(bool act_high);
void dispc_lcd_enable_signal(bool enable);
void dispc_pck_free_enable(bool enable);
void dispc_enable_fifohandcheck(bool enable);
void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
void dispc_set_lcd_size(u16 width, u16 height);
void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
void dispc_set_digit_size(u16 width, u16 height);
u32 dispc_get_plane_fifo_size(enum omap_plane plane);
void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
......@@ -359,7 +359,8 @@ int dispc_setup_plane(enum omap_plane plane,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror,
u8 global_alpha);
u8 global_alpha, u8 pre_mult_alpha,
enum omap_channel channel);
bool dispc_go_busy(enum omap_channel channel);
void dispc_go(enum omap_channel channel);
......@@ -368,9 +369,11 @@ bool dispc_is_channel_enabled(enum omap_channel channel);
int dispc_enable_plane(enum omap_plane plane, bool enable);
void dispc_enable_replication(enum omap_plane plane, bool enable);
void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
void dispc_set_tft_data_lines(u8 data_lines);
void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
void dispc_set_parallel_interface_mode(enum omap_channel channel,
enum omap_parallel_interface_mode mode);
void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines);
void dispc_set_lcd_display_type(enum omap_channel channel,
enum omap_lcd_display_type type);
void dispc_set_loadmode(enum omap_dss_load_mode mode);
void dispc_set_default_color(enum omap_channel channel, u32 color);
......@@ -387,17 +390,21 @@ bool dispc_trans_key_enabled(enum omap_channel ch);
bool dispc_alpha_blending_enabled(enum omap_channel ch);
bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
void dispc_set_lcd_timings(struct omap_video_timings *timings);
void dispc_set_lcd_timings(enum omap_channel channel,
struct omap_video_timings *timings);
unsigned long dispc_fclk_rate(void);
unsigned long dispc_lclk_rate(void);
unsigned long dispc_pclk_rate(void);
void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
unsigned long dispc_lclk_rate(enum omap_channel channel);
unsigned long dispc_pclk_rate(enum omap_channel channel);
void dispc_set_pol_freq(enum omap_channel channel,
enum omap_panel_config config, u8 acbi, u8 acb);
void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
struct dispc_clock_info *cinfo);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);
int dispc_set_clock_div(struct dispc_clock_info *cinfo);
int dispc_get_clock_div(struct dispc_clock_info *cinfo);
int dispc_set_clock_div(enum omap_channel channel,
struct dispc_clock_info *cinfo);
int dispc_get_clock_div(enum omap_channel channel,
struct dispc_clock_info *cinfo);
/* VENC */
......@@ -424,8 +431,8 @@ void rfbi_dump_regs(struct seq_file *s);
int rfbi_configure(int rfbi_module, int bpp, int lines);
void rfbi_enable_rfbi(bool enable);
void rfbi_transfer_area(u16 width, u16 height,
void (callback)(void *data), void *data);
void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
u16 height, void (callback)(void *data), void *data);
void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
unsigned long rfbi_get_max_tx_rate(void);
int rfbi_init_display(struct omap_dss_device *display);
......
......@@ -82,6 +82,18 @@ static const enum omap_display_type omap3_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_VENC,
};
static const enum omap_display_type omap4_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DISPLAY_TYPE_VENC,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
OMAP_DISPLAY_TYPE_DSI,
};
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
......@@ -127,6 +139,10 @@ static struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
.has_feature =
FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL |
FEAT_PCKFREEENABLE | FEAT_FUNCGATED,
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap2_dss_supported_displays,
......@@ -134,11 +150,29 @@ static struct omap_dss_features omap2_dss_features = {
};
/* OMAP3 DSS Features */
static struct omap_dss_features omap3_dss_features = {
static struct omap_dss_features omap3430_dss_features = {
.reg_fields = omap3_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_FUNCGATED,
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
};
static struct omap_dss_features omap3630_dss_features = {
.reg_fields = omap3_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
.has_feature = FEAT_GLOBAL_ALPHA,
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED,
.num_mgrs = 2,
.num_ovls = 3,
......@@ -146,6 +180,21 @@ static struct omap_dss_features omap3_dss_features = {
.supported_color_modes = omap3_dss_supported_color_modes,
};
/* OMAP4 DSS Features */
static struct omap_dss_features omap4_dss_features = {
.reg_fields = omap3_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
.has_feature =
FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
FEAT_MGR_LCD2,
.num_mgrs = 3,
.num_ovls = 3,
.supported_displays = omap4_dss_supported_displays,
.supported_color_modes = omap3_dss_supported_color_modes,
};
/* Functions returning values related to a DSS feature */
int dss_feat_get_num_mgrs(void)
{
......@@ -167,6 +216,13 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
return omap_current_dss_features->supported_color_modes[plane];
}
bool dss_feat_color_mode_supported(enum omap_plane plane,
enum omap_color_mode color_mode)
{
return omap_current_dss_features->supported_color_modes[plane] &
color_mode;
}
/* DSS has_feature check */
bool dss_has_feature(enum dss_feat_id id)
{
......@@ -186,6 +242,10 @@ void dss_features_init(void)
{
if (cpu_is_omap24xx())
omap_current_dss_features = &omap2_dss_features;
else if (cpu_is_omap3630())
omap_current_dss_features = &omap3630_dss_features;
else if (cpu_is_omap34xx())
omap_current_dss_features = &omap3430_dss_features;
else
omap_current_dss_features = &omap3_dss_features;
omap_current_dss_features = &omap4_dss_features;
}
......@@ -20,13 +20,19 @@
#ifndef __OMAP2_DSS_FEATURES_H
#define __OMAP2_DSS_FEATURES_H
#define MAX_DSS_MANAGERS 2
#define MAX_DSS_MANAGERS 3
#define MAX_DSS_OVERLAYS 3
/* DSS has feature id */
enum dss_feat_id {
FEAT_GLOBAL_ALPHA = 1 << 0,
FEAT_GLOBAL_ALPHA_VID1 = 1 << 1,
FEAT_PRE_MULT_ALPHA = 1 << 2,
FEAT_LCDENABLEPOL = 1 << 3,
FEAT_LCDENABLESIGNAL = 1 << 4,
FEAT_PCKFREEENABLE = 1 << 5,
FEAT_FUNCGATED = 1 << 6,
FEAT_MGR_LCD2 = 1 << 7,
};
/* DSS register field id */
......@@ -43,6 +49,8 @@ int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
bool dss_feat_color_mode_supported(enum omap_plane plane,
enum omap_color_mode color_mode);
bool dss_has_feature(enum dss_feat_id id);
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
......
......@@ -406,6 +406,7 @@ struct overlay_cache_data {
u16 out_width; /* if 0, out_width == width */
u16 out_height; /* if 0, out_height == height */
u8 global_alpha;
u8 pre_mult_alpha;
enum omap_channel channel;
bool replication;
......@@ -512,11 +513,14 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
unsigned long timeout = msecs_to_jiffies(500);
u32 irq;
if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD;
else
irq = DISPC_IRQ_VSYNC;
} else {
if (mgr->id == OMAP_DSS_CHANNEL_LCD)
irq = DISPC_IRQ_VSYNC;
else
irq = DISPC_IRQ_VSYNC2;
}
return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
}
......@@ -524,7 +528,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
struct manager_cache_data *mc;
enum omap_channel channel;
u32 irq;
int r;
int i;
......@@ -535,7 +538,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
......@@ -543,11 +545,14 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
irq = DISPC_IRQ_FRAMEDONE;
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
DISPC_IRQ_FRAMEDONE
: DISPC_IRQ_FRAMEDONE2;
} else {
irq = DISPC_IRQ_VSYNC;
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
DISPC_IRQ_VSYNC
: DISPC_IRQ_VSYNC2;
}
channel = OMAP_DSS_CHANNEL_LCD;
}
mc = &dss_cache.manager_cache[mgr->id];
......@@ -594,7 +599,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
{
unsigned long timeout = msecs_to_jiffies(500);
enum omap_channel channel;
struct overlay_cache_data *oc;
struct omap_dss_device *dssdev;
u32 irq;
......@@ -611,7 +615,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
channel = OMAP_DSS_CHANNEL_DIGIT;
} else {
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
enum omap_dss_update_mode mode;
......@@ -619,11 +622,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (mode != OMAP_DSS_UPDATE_AUTO)
return 0;
irq = DISPC_IRQ_FRAMEDONE;
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
DISPC_IRQ_FRAMEDONE
: DISPC_IRQ_FRAMEDONE2;
} else {
irq = DISPC_IRQ_VSYNC;
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
DISPC_IRQ_VSYNC
: DISPC_IRQ_VSYNC2;
}
channel = OMAP_DSS_CHANNEL_LCD;
}
oc = &dss_cache.overlay_cache[ovl->id];
......@@ -842,7 +848,9 @@ static int configure_overlay(enum omap_plane plane)
c->rotation_type,
c->rotation,
c->mirror,
c->global_alpha);
c->global_alpha,
c->pre_mult_alpha,
c->channel);
if (r) {
/* this shouldn't happen */
......@@ -894,10 +902,10 @@ static int configure_dispc(void)
r = 0;
busy = false;
mgr_busy[0] = dispc_go_busy(0);
mgr_busy[1] = dispc_go_busy(1);
mgr_go[0] = false;
mgr_go[1] = false;
for (i = 0; i < num_mgrs; i++) {
mgr_busy[i] = dispc_go_busy(i);
mgr_go[i] = false;
}
/* Commit overlay settings */
for (i = 0; i < num_ovls; ++i) {
......@@ -1156,9 +1164,10 @@ static void dss_apply_irq_handler(void *data, u32 mask)
const int num_mgrs = dss_feat_get_num_mgrs();
int i, r;
bool mgr_busy[MAX_DSS_MANAGERS];
u32 irq_mask;
mgr_busy[0] = dispc_go_busy(0);
mgr_busy[1] = dispc_go_busy(1);
for (i = 0; i < num_mgrs; i++)
mgr_busy[i] = dispc_go_busy(i);
spin_lock(&dss_cache.lock);
......@@ -1179,8 +1188,8 @@ static void dss_apply_irq_handler(void *data, u32 mask)
goto end;
/* re-read busy flags */
mgr_busy[0] = dispc_go_busy(0);
mgr_busy[1] = dispc_go_busy(1);
for (i = 0; i < num_mgrs; i++)
mgr_busy[i] = dispc_go_busy(i);
/* keep running as long as there are busy managers, so that
* we can collect overlay-applied information */
......@@ -1189,9 +1198,12 @@ static void dss_apply_irq_handler(void *data, u32 mask)
goto end;
}
omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
DISPC_IRQ_EVSYNC_EVEN);
irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
DISPC_IRQ_EVSYNC_EVEN;
if (dss_has_feature(FEAT_MGR_LCD2))
irq_mask |= DISPC_IRQ_VSYNC2;
omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask);
dss_cache.irq_enabled = false;
end:
......@@ -1265,6 +1277,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->out_width = ovl->info.out_width;
oc->out_height = ovl->info.out_height;
oc->global_alpha = ovl->info.global_alpha;
oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
oc->replication =
dss_use_replication(dssdev, ovl->info.color_mode);
......@@ -1383,9 +1396,14 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
r = 0;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
if (!dss_cache.irq_enabled) {
r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
DISPC_IRQ_EVSYNC_EVEN);
u32 mask;
mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
DISPC_IRQ_EVSYNC_EVEN;
if (dss_has_feature(FEAT_MGR_LCD2))
mask |= DISPC_IRQ_VSYNC2;
r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
dss_cache.irq_enabled = true;
}
configure_dispc();
......@@ -1477,6 +1495,10 @@ int dss_init_overlay_managers(struct platform_device *pdev)
mgr->name = "tv";
mgr->id = OMAP_DSS_CHANNEL_DIGIT;
break;
case 2:
mgr->name = "lcd2";
mgr->id = OMAP_DSS_CHANNEL_LCD2;
break;
}
mgr->set_device = &omap_dss_set_device;
......
......@@ -257,6 +257,43 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
return size;
}
static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n",
ovl->info.pre_mult_alpha);
}
static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
const char *buf, size_t size)
{
int r;
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
/* only GFX and Video2 plane support pre alpha multiplied
* set zero for Video1 plane
*/
if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
ovl->id == OMAP_DSS_VIDEO1)
info.pre_mult_alpha = 0;
else
info.pre_mult_alpha = simple_strtoul(buf, NULL, 10);
r = ovl->set_overlay_info(ovl, &info);
if (r)
return r;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
return r;
}
return size;
}
struct overlay_attribute {
struct attribute attr;
ssize_t (*show)(struct omap_overlay *, char *);
......@@ -280,6 +317,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
overlay_enabled_show, overlay_enabled_store);
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
overlay_global_alpha_show, overlay_global_alpha_store);
static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
overlay_pre_mult_alpha_show,
overlay_pre_mult_alpha_store);
static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_name.attr,
......@@ -290,6 +330,7 @@ static struct attribute *overlay_sysfs_attrs[] = {
&overlay_attr_output_size.attr,
&overlay_attr_enabled.attr,
&overlay_attr_global_alpha.attr,
&overlay_attr_pre_mult_alpha.attr,
NULL
};
......@@ -623,12 +664,22 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
int i;
struct omap_overlay_manager *lcd_mgr;
struct omap_overlay_manager *tv_mgr;
struct omap_overlay_manager *lcd2_mgr = NULL;
struct omap_overlay_manager *mgr = NULL;
lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
if (dss_has_feature(FEAT_MGR_LCD2))
lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2);
if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
if (!lcd2_mgr->device || force) {
if (lcd2_mgr->device)
lcd2_mgr->unset_device(lcd2_mgr);
lcd2_mgr->set_device(lcd2_mgr, dssdev);
mgr = lcd2_mgr;
}
} else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
if (!lcd_mgr->device || force) {
if (lcd_mgr->device)
lcd_mgr->unset_device(lcd_mgr);
......
......@@ -301,8 +301,8 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
void rfbi_transfer_area(u16 width, u16 height,
void (callback)(void *data), void *data)
void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
u16 height, void (*callback)(void *data), void *data)
{
u32 l;
......@@ -311,9 +311,9 @@ void rfbi_transfer_area(u16 width, u16 height,
DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
dispc_set_lcd_size(width, height);
dispc_set_lcd_size(dssdev->manager->id, width, height);
dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
dispc_enable_channel(dssdev->manager->id, true);
rfbi.framedone_callback = callback;
rfbi.framedone_callback_data = data;
......@@ -887,7 +887,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h, true);
dispc_set_lcd_size(*w, *h);
dispc_set_lcd_size(dssdev->manager->id, *w, *h);
}
return 0;
......@@ -899,7 +899,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev,
void (*callback)(void *), void *data)
{
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
rfbi_transfer_area(w, h, callback, data);
rfbi_transfer_area(dssdev, w, h, callback, data);
} else {
struct omap_overlay *ovl;
void __iomem *addr;
......@@ -1018,11 +1018,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
goto err1;
}
dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
dispc_set_lcd_display_type(dssdev->manager->id,
OMAP_DSS_LCD_DISPLAY_TFT);
dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
dispc_set_parallel_interface_mode(dssdev->manager->id,
OMAP_DSS_PARALLELMODE_RFBI);
dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size);
rfbi_configure(dssdev->phy.rfbi.channel,
dssdev->ctrl.pixel_size,
......
......@@ -35,12 +35,16 @@ static struct {
struct regulator *vdds_sdi_reg;
} sdi;
static void sdi_basic_init(void)
static void sdi_basic_init(struct omap_dss_device *dssdev)
{
dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
dispc_set_parallel_interface_mode(dssdev->manager->id,
OMAP_DSS_PARALLELMODE_BYPASS);
dispc_set_lcd_display_type(dssdev->manager->id,
OMAP_DSS_LCD_DISPLAY_TFT);
dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
dispc_set_tft_data_lines(24);
dispc_set_tft_data_lines(dssdev->manager->id, 24);
dispc_lcd_enable_signal_polarity(1);
}
......@@ -68,20 +72,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
if (!sdi.skip_init)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
sdi_basic_init();
sdi_basic_init(dssdev);
/* 15.5.9.1.2 */
dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
dssdev->panel.acb);
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
dssdev->panel.acbi, dssdev->panel.acb);
if (!sdi.skip_init) {
r = dss_calc_clock_div(1, t->pixel_clock * 1000,
&dss_cinfo, &dispc_cinfo);
} else {
r = dss_get_clock_div(&dss_cinfo);
r = dispc_get_clock_div(&dispc_cinfo);
r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo);
}
if (r)
......@@ -102,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
}
dispc_set_lcd_timings(t);
dispc_set_lcd_timings(dssdev->manager->id, t);
r = dss_set_clock_div(&dss_cinfo);
if (r)
goto err2;
r = dispc_set_clock_div(&dispc_cinfo);
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
goto err2;
......
......@@ -2132,8 +2132,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
char *str, *options, *this_opt;
int r = 0;
str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
strcpy(str, def_mode);
str = kstrdup(def_mode, GFP_KERNEL);
if (!str)
return -ENOMEM;
options = str;
while (!r && (this_opt = strsep(&options, ",")) != NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment