diff options
author | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-10-15 00:19:52 (GMT) |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-10-15 00:19:52 (GMT) |
commit | ef26b7943c5821aaff1efc14c098840c49fe15c0 (patch) | |
tree | a91834ef396633c5c56a0597c2fc525e0684fc30 /drivers/video/omap2 | |
parent | 07aaae44f5a3962c3a410a6dd7936dfa7dece2b9 (diff) | |
parent | 3e28189038bb831512cf4f8313e1aead97c3e63f (diff) | |
download | linux-fsl-qoriq-ef26b7943c5821aaff1efc14c098840c49fe15c0.tar.xz |
Merge branch 'for-florian' of git://gitorious.org/linux-omap-dss2/linux into fbdev-next
Diffstat (limited to 'drivers/video/omap2')
33 files changed, 5811 insertions, 3173 deletions
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 609a280..8d8e1fe 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -10,6 +10,13 @@ config PANEL_GENERIC_DPI Supports LCD Panel used in TI SDP3430 and EVM boards, OMAP3517 EVM boards and CM-T35. +config PANEL_DVI + tristate "DVI output" + depends on OMAP2_DSS_DPI + help + Driver for external monitors, connected via DVI. The driver uses i2c + to read EDID information from the monitor. + config PANEL_LGPHILIPS_LB035Q02 tristate "LG.Philips LB035Q02 LCD Panel" depends on OMAP2_DSS_DPI && SPI @@ -19,20 +26,30 @@ config PANEL_LGPHILIPS_LB035Q02 config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on OMAP2_DSS_DPI - select BACKLIGHT_CLASS_DEVICE + depends on BACKLIGHT_CLASS_DEVICE help LCD Panel used in TI's SDP3430 and EVM boards config PANEL_NEC_NL8048HL11_01B tristate "NEC NL8048HL11-01B Panel" depends on OMAP2_DSS_DPI + depends on SPI + depends on BACKLIGHT_CLASS_DEVICE help This NEC NL8048HL11-01B panel is TFT LCD used in the Zoom2/3/3630 sdp boards. +config PANEL_PICODLP + tristate "TI PICO DLP mini-projector" + depends on OMAP2_DSS && I2C + help + A mini-projector used in TI's SDP4430 and EVM boards + For more info please visit http://www.dlp.com/projector/ + config PANEL_TAAL tristate "Taal DSI Panel" depends on OMAP2_DSS_DSI + depends on BACKLIGHT_CLASS_DEVICE help Taal DSI command mode panel from TPO. @@ -45,7 +62,14 @@ config PANEL_TPO_TD043MTEA1 config PANEL_ACX565AKM tristate "ACX565AKM Panel" depends on OMAP2_DSS_SDI && SPI - select BACKLIGHT_CLASS_DEVICE + depends on BACKLIGHT_CLASS_DEVICE help This is the LCD panel used on Nokia N900 + +config PANEL_N8X0 + tristate "N8X0 Panel" + depends on OMAP2_DSS_RFBI && SPI + depends on BACKLIGHT_CLASS_DEVICE + help + This is the LCD panel used on Nokia N8x0 endmenu diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index 0f601ab3a..fbfafc6 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -1,8 +1,11 @@ obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o +obj-$(CONFIG_PANEL_DVI) += panel-dvi.o obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o +obj-$(CONFIG_PANEL_PICODLP) += panel-picodlp.o obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o +obj-$(CONFIG_PANEL_N8X0) += panel-n8x0.o diff --git a/drivers/video/omap2/displays/panel-dvi.c b/drivers/video/omap2/displays/panel-dvi.c new file mode 100644 index 0000000..03eb14a --- /dev/null +++ b/drivers/video/omap2/displays/panel-dvi.c @@ -0,0 +1,363 @@ +/* + * DVI output support + * + * Copyright (C) 2011 Texas Instruments Inc + * Author: Tomi Valkeinen <tomi.valkeinen@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/slab.h> +#include <video/omapdss.h> +#include <linux/i2c.h> +#include <drm/drm_edid.h> + +#include <video/omap-panel-dvi.h> + +static const struct omap_video_timings panel_dvi_default_timings = { + .x_res = 640, + .y_res = 480, + + .pixel_clock = 23500, + + .hfp = 48, + .hsw = 32, + .hbp = 80, + + .vfp = 3, + .vsw = 4, + .vbp = 7, +}; + +struct panel_drv_data { + struct omap_dss_device *dssdev; + + struct mutex lock; +}; + +static inline struct panel_dvi_platform_data +*get_pdata(const struct omap_dss_device *dssdev) +{ + return dssdev->data; +} + +static int panel_dvi_power_on(struct omap_dss_device *dssdev) +{ + struct panel_dvi_platform_data *pdata = get_pdata(dssdev); + int r; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + + if (pdata->platform_enable) { + r = pdata->platform_enable(dssdev); + if (r) + goto err1; + } + + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: + return r; +} + +static void panel_dvi_power_off(struct omap_dss_device *dssdev) +{ + struct panel_dvi_platform_data *pdata = get_pdata(dssdev); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; + + if (pdata->platform_disable) + pdata->platform_disable(dssdev); + + omapdss_dpi_display_disable(dssdev); +} + +static int panel_dvi_probe(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata; + + ddata = kzalloc(sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + dssdev->panel.timings = panel_dvi_default_timings; + dssdev->panel.config = OMAP_DSS_LCD_TFT; + + ddata->dssdev = dssdev; + mutex_init(&ddata->lock); + + dev_set_drvdata(&dssdev->dev, ddata); + + return 0; +} + +static void __exit panel_dvi_remove(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ddata->lock); + + dev_set_drvdata(&dssdev->dev, NULL); + + mutex_unlock(&ddata->lock); + + kfree(ddata); +} + +static int panel_dvi_enable(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&ddata->lock); + + r = panel_dvi_power_on(dssdev); + if (r == 0) + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&ddata->lock); + + return r; +} + +static void panel_dvi_disable(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ddata->lock); + + panel_dvi_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&ddata->lock); +} + +static int panel_dvi_suspend(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ddata->lock); + + panel_dvi_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + + mutex_unlock(&ddata->lock); + + return 0; +} + +static int panel_dvi_resume(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&ddata->lock); + + r = panel_dvi_power_on(dssdev); + if (r == 0) + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&ddata->lock); + + return r; +} + +static void panel_dvi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ddata->lock); + dpi_set_timings(dssdev, timings); + mutex_unlock(&ddata->lock); +} + +static void panel_dvi_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ddata->lock); + *timings = dssdev->panel.timings; + mutex_unlock(&ddata->lock); +} + +static int panel_dvi_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&ddata->lock); + r = dpi_check_timings(dssdev, timings); + mutex_unlock(&ddata->lock); + + return r; +} + + +static int panel_dvi_ddc_read(struct i2c_adapter *adapter, + unsigned char *buf, u16 count, u8 offset) +{ + int r, retries; + + for (retries = 3; retries > 0; retries--) { + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &offset, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + } + }; + + r = i2c_transfer(adapter, msgs, 2); + if (r == 2) + return 0; + + if (r != -EAGAIN) + break; + } + + return r < 0 ? r : -EIO; +} + +static int panel_dvi_read_edid(struct omap_dss_device *dssdev, + u8 *edid, int len) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + struct panel_dvi_platform_data *pdata = get_pdata(dssdev); + struct i2c_adapter *adapter; + int r, l, bytes_read; + + mutex_lock(&ddata->lock); + + if (pdata->i2c_bus_num == 0) { + r = -ENODEV; + goto err; + } + + adapter = i2c_get_adapter(pdata->i2c_bus_num); + if (!adapter) { + dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", + pdata->i2c_bus_num); + r = -EINVAL; + goto err; + } + + l = min(EDID_LENGTH, len); + r = panel_dvi_ddc_read(adapter, edid, l, 0); + if (r) + goto err; + + bytes_read = l; + + /* if there are extensions, read second block */ + if (len > EDID_LENGTH && edid[0x7e] > 0) { + l = min(EDID_LENGTH, len - EDID_LENGTH); + + r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH, + l, EDID_LENGTH); + if (r) + goto err; + + bytes_read += l; + } + + mutex_unlock(&ddata->lock); + + return bytes_read; + +err: + mutex_unlock(&ddata->lock); + return r; +} + +static bool panel_dvi_detect(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); + struct panel_dvi_platform_data *pdata = get_pdata(dssdev); + struct i2c_adapter *adapter; + unsigned char out; + int r; + + mutex_lock(&ddata->lock); + + if (pdata->i2c_bus_num == 0) + goto out; + + adapter = i2c_get_adapter(pdata->i2c_bus_num); + if (!adapter) + goto out; + + r = panel_dvi_ddc_read(adapter, &out, 1, 0); + + mutex_unlock(&ddata->lock); + + return r == 0; + +out: + mutex_unlock(&ddata->lock); + return true; +} + +static struct omap_dss_driver panel_dvi_driver = { + .probe = panel_dvi_probe, + .remove = __exit_p(panel_dvi_remove), + + .enable = panel_dvi_enable, + .disable = panel_dvi_disable, + .suspend = panel_dvi_suspend, + .resume = panel_dvi_resume, + + .set_timings = panel_dvi_set_timings, + .get_timings = panel_dvi_get_timings, + .check_timings = panel_dvi_check_timings, + + .read_edid = panel_dvi_read_edid, + .detect = panel_dvi_detect, + + .driver = { + .name = "dvi", + .owner = THIS_MODULE, + }, +}; + +static int __init panel_dvi_init(void) +{ + return omap_dss_register_driver(&panel_dvi_driver); +} + +static void __exit panel_dvi_exit(void) +{ + omap_dss_unregister_driver(&panel_dvi_driver); +} + +module_init(panel_dvi_init); +module_exit(panel_dvi_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 9c90f75..519c47d 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -58,30 +58,6 @@ struct panel_config { /* 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 */ { { @@ -232,6 +208,95 @@ static struct panel_config generic_dpi_panels[] = { .power_off_delay = 0, .name = "powertip_ph480272t", }, + + /* Innolux AT070TN83 */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 40000, + + .hsw = 48, + .hfp = 1, + .hbp = 1, + + .vsw = 3, + .vfp = 12, + .vbp = 25, + }, + .acbi = 0x0, + .acb = 0x28, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "innolux_at070tn83", + }, + + /* NEC NL2432DR22-11B */ + { + { + .x_res = 240, + .y_res = 320, + + .pixel_clock = 5400, + + .hsw = 3, + .hfp = 3, + .hbp = 39, + + .vsw = 1, + .vfp = 2, + .vbp = 7, + }, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .name = "nec_nl2432dr22-11b", + }, + + /* Unknown panel used in OMAP H4 */ + { + { + .x_res = 240, + .y_res = 320, + + .pixel_clock = 6250, + + .hsw = 15, + .hfp = 15, + .hbp = 60, + + .vsw = 1, + .vfp = 1, + .vbp = 1, + }, + .config = OMAP_DSS_LCD_TFT, + + .name = "h4", + }, + + /* Unknown panel used in Samsung OMAP2 Apollon */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 6250, + + .hsw = 41, + .hfp = 2, + .hbp = 2, + + .vsw = 10, + .vfp = 2, + .vbp = 2, + }, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + + .name = "apollon", + }, }; struct panel_drv_data { diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c new file mode 100644 index 0000000..150e8ba --- /dev/null +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -0,0 +1,747 @@ +/* #define DEBUG */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include <linux/backlight.h> +#include <linux/fb.h> + +#include <video/omapdss.h> +#include <video/omap-panel-n8x0.h> + +#define BLIZZARD_REV_CODE 0x00 +#define BLIZZARD_CONFIG 0x02 +#define BLIZZARD_PLL_DIV 0x04 +#define BLIZZARD_PLL_LOCK_RANGE 0x06 +#define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08 +#define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a +#define BLIZZARD_PLL_MODE 0x0c +#define BLIZZARD_CLK_SRC 0x0e +#define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 +#define BLIZZARD_MEM_BANK0_STATUS 0x14 +#define BLIZZARD_PANEL_CONFIGURATION 0x28 +#define BLIZZARD_HDISP 0x2a +#define BLIZZARD_HNDP 0x2c +#define BLIZZARD_VDISP0 0x2e +#define BLIZZARD_VDISP1 0x30 +#define BLIZZARD_VNDP 0x32 +#define BLIZZARD_HSW 0x34 +#define BLIZZARD_VSW 0x38 +#define BLIZZARD_DISPLAY_MODE 0x68 +#define BLIZZARD_INPUT_WIN_X_START_0 0x6c +#define BLIZZARD_DATA_SOURCE_SELECT 0x8e +#define BLIZZARD_DISP_MEM_DATA_PORT 0x90 +#define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 +#define BLIZZARD_POWER_SAVE 0xE6 +#define BLIZZARD_NDISP_CTRL_STATUS 0xE8 + +/* Data source select */ +/* For S1D13745 */ +#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 +#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 +#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 +#define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 +/* For S1D13744 */ +#define BLIZZARD_SRC_WRITE_LCD 0x00 +#define BLIZZARD_SRC_BLT_LCD 0x06 + +#define BLIZZARD_COLOR_RGB565 0x01 +#define BLIZZARD_COLOR_YUV420 0x09 + +#define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ +#define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ + +#define MIPID_CMD_READ_DISP_ID 0x04 +#define MIPID_CMD_READ_RED 0x06 +#define MIPID_CMD_READ_GREEN 0x07 +#define MIPID_CMD_READ_BLUE 0x08 +#define MIPID_CMD_READ_DISP_STATUS 0x09 +#define MIPID_CMD_RDDSDR 0x0F +#define MIPID_CMD_SLEEP_IN 0x10 +#define MIPID_CMD_SLEEP_OUT 0x11 +#define MIPID_CMD_DISP_OFF 0x28 +#define MIPID_CMD_DISP_ON 0x29 + +static struct panel_drv_data { + struct mutex lock; + + struct omap_dss_device *dssdev; + struct spi_device *spidev; + struct backlight_device *bldev; + + int blizzard_ver; +} s_drv_data; + + +static inline +struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev) +{ + return dssdev->data; +} + +static inline +struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev) +{ + return &s_drv_data; +} + + +static inline void blizzard_cmd(u8 cmd) +{ + omap_rfbi_write_command(&cmd, 1); +} + +static inline void blizzard_write(u8 cmd, const u8 *buf, int len) +{ + omap_rfbi_write_command(&cmd, 1); + omap_rfbi_write_data(buf, len); +} + +static inline void blizzard_read(u8 cmd, u8 *buf, int len) +{ + omap_rfbi_write_command(&cmd, 1); + omap_rfbi_read_data(buf, len); +} + +static u8 blizzard_read_reg(u8 cmd) +{ + u8 data; + blizzard_read(cmd, &data, 1); + return data; +} + +static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev, + int x, int y, int w, int h) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + u8 tmp[18]; + int x_end, y_end; + + x_end = x + w - 1; + y_end = y + h - 1; + + tmp[0] = x; + tmp[1] = x >> 8; + tmp[2] = y; + tmp[3] = y >> 8; + tmp[4] = x_end; + tmp[5] = x_end >> 8; + tmp[6] = y_end; + tmp[7] = y_end >> 8; + + /* scaling? */ + tmp[8] = x; + tmp[9] = x >> 8; + tmp[10] = y; + tmp[11] = y >> 8; + tmp[12] = x_end; + tmp[13] = x_end >> 8; + tmp[14] = y_end; + tmp[15] = y_end >> 8; + + tmp[16] = BLIZZARD_COLOR_RGB565; + + if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745) + tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; + else + tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ? + BLIZZARD_SRC_WRITE_LCD : + BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; + + omap_rfbi_configure(dssdev, 16, 8); + + blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18); + + omap_rfbi_configure(dssdev, 16, 16); +} + +static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf, + int wlen, u8 *rbuf, int rlen) +{ + struct spi_message m; + struct spi_transfer *x, xfer[4]; + u16 w; + int r; + + spi_message_init(&m); + + memset(xfer, 0, sizeof(xfer)); + x = &xfer[0]; + + cmd &= 0xff; + x->tx_buf = &cmd; + x->bits_per_word = 9; + x->len = 2; + spi_message_add_tail(x, &m); + + if (wlen) { + x++; + x->tx_buf = wbuf; + x->len = wlen; + x->bits_per_word = 9; + spi_message_add_tail(x, &m); + } + + if (rlen) { + x++; + x->rx_buf = &w; + x->len = 1; + spi_message_add_tail(x, &m); + + if (rlen > 1) { + /* Arrange for the extra clock before the first + * data bit. + */ + x->bits_per_word = 9; + x->len = 2; + + x++; + x->rx_buf = &rbuf[1]; + x->len = rlen - 1; + spi_message_add_tail(x, &m); + } + } + + r = spi_sync(spi, &m); + if (r < 0) + dev_dbg(&spi->dev, "spi_sync %d\n", r); + + if (rlen) + rbuf[0] = w & 0xff; +} + +static inline void mipid_cmd(struct spi_device *spi, int cmd) +{ + mipid_transfer(spi, cmd, NULL, 0, NULL, 0); +} + +static inline void mipid_write(struct spi_device *spi, + int reg, const u8 *buf, int len) +{ + mipid_transfer(spi, reg, buf, len, NULL, 0); +} + +static inline void mipid_read(struct spi_device *spi, + int reg, u8 *buf, int len) +{ + mipid_transfer(spi, reg, NULL, 0, buf, len); +} + +static void set_data_lines(struct spi_device *spi, int data_lines) +{ + u16 par; + + switch (data_lines) { + case 16: + par = 0x150; + break; + case 18: + par = 0x160; + break; + case 24: + par = 0x170; + break; + } + + mipid_write(spi, 0x3a, (u8 *)&par, 2); +} + +static void send_init_string(struct spi_device *spi) +{ + u16 initpar[] = { 0x0102, 0x0100, 0x0100 }; + mipid_write(spi, 0xc2, (u8 *)initpar, sizeof(initpar)); +} + +static void send_display_on(struct spi_device *spi) +{ + mipid_cmd(spi, MIPID_CMD_DISP_ON); +} + +static void send_display_off(struct spi_device *spi) +{ + mipid_cmd(spi, MIPID_CMD_DISP_OFF); +} + +static void send_sleep_out(struct spi_device *spi) +{ + mipid_cmd(spi, MIPID_CMD_SLEEP_OUT); + msleep(120); +} + +static void send_sleep_in(struct spi_device *spi) +{ + mipid_cmd(spi, MIPID_CMD_SLEEP_IN); + msleep(50); +} + +static int n8x0_panel_power_on(struct omap_dss_device *dssdev) +{ + int r; + struct panel_n8x0_data *bdata = get_board_data(dssdev); + struct panel_drv_data *ddata = get_drv_data(dssdev); + struct spi_device *spi = ddata->spidev; + u8 rev, conf; + u8 display_id[3]; + const char *panel_name; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + gpio_direction_output(bdata->ctrl_pwrdown, 1); + + if (bdata->platform_enable) { + r = bdata->platform_enable(dssdev); + if (r) + goto err_plat_en; + } + + r = omapdss_rfbi_display_enable(dssdev); + if (r) + goto err_rfbi_en; + + rev = blizzard_read_reg(BLIZZARD_REV_CODE); + conf = blizzard_read_reg(BLIZZARD_CONFIG); + + switch (rev & 0xfc) { + case 0x9c: + ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744; + dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d " + "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); + break; + case 0xa4: + ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745; + dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d " + "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); + break; + default: + dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev); + r = -ENODEV; + goto err_inv_chip; + } + + /* panel */ + + gpio_direction_output(bdata->panel_reset, 1); + + mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3); + dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n", + display_id[0], display_id[1], display_id[2]); + + switch (display_id[0]) { + case 0x45: + panel_name = "lph8923"; + break; + case 0x83: + panel_name = "ls041y3"; + break; + default: + dev_err(&dssdev->dev, "invalid display ID 0x%x\n", + display_id[0]); + r = -ENODEV; + goto err_inv_panel; + } + + dev_info(&dssdev->dev, "%s rev %02x LCD detected\n", + panel_name, display_id[1]); + + send_sleep_out(spi); + send_init_string(spi); + set_data_lines(spi, 24); + send_display_on(spi); + + return 0; + +err_inv_panel: + /* + * HACK: we should turn off the panel here, but there is some problem + * with the initialization sequence, and we fail to init the panel if we + * have turned it off + */ + /* gpio_direction_output(bdata->panel_reset, 0); */ +err_inv_chip: + omapdss_rfbi_display_disable(dssdev); +err_rfbi_en: + if (bdata->platform_disable) + bdata->platform_disable(dssdev); +err_plat_en: + gpio_direction_output(bdata->ctrl_pwrdown, 0); + return r; +} + +static void n8x0_panel_power_off(struct omap_dss_device *dssdev) +{ + struct panel_n8x0_data *bdata = get_board_data(dssdev); + struct panel_drv_data *ddata = get_drv_data(dssdev); + struct spi_device *spi = ddata->spidev; + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; + + send_display_off(spi); + send_sleep_in(spi); + + if (bdata->platform_disable) + bdata->platform_disable(dssdev); + + /* + * HACK: we should turn off the panel here, but there is some problem + * with the initialization sequence, and we fail to init the panel if we + * have turned it off + */ + /* gpio_direction_output(bdata->panel_reset, 0); */ + gpio_direction_output(bdata->ctrl_pwrdown, 0); + omapdss_rfbi_display_disable(dssdev); +} + +static const struct rfbi_timings n8x0_panel_timings = { + .cs_on_time = 0, + + .we_on_time = 9000, + .we_off_time = 18000, + .we_cycle_time = 36000, + + .re_on_time = 9000, + .re_off_time = 27000, + .re_cycle_time = 36000, + + .access_time = 27000, + .cs_off_time = 36000, + + .cs_pulse_width = 0, +}; + +static int n8x0_bl_update_status(struct backlight_device *dev) +{ + struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); + struct panel_n8x0_data *bdata = get_board_data(dssdev); + struct panel_drv_data *ddata = get_drv_data(dssdev); + int r; + int level; + + mutex_lock(&ddata->lock); + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) + level = dev->props.brightness; + else + level = 0; + + dev_dbg(&dssdev->dev, "update brightness to %d\n", level); + + if (!bdata->set_backlight) + r = -EINVAL; + else + r = bdata->set_backlight(dssdev, level); + + mutex_unlock(&ddata->lock); + + return r; +} + +static int n8x0_bl_get_intensity(struct backlight_device *dev) +{ + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) + return dev->props.brightness; + + return 0; +} + +static const struct backlight_ops n8x0_bl_ops = { + .get_brightness = n8x0_bl_get_intensity, + .update_status = n8x0_bl_update_status, +}; + +static int n8x0_panel_probe(struct omap_dss_device *dssdev) +{ + struct panel_n8x0_data *bdata = get_board_data(dssdev); + struct panel_drv_data *ddata; + struct backlight_device *bldev; + struct backlight_properties props; + int r; + + dev_dbg(&dssdev->dev, "probe\n"); + + if (!bdata) + return -EINVAL; + + s_drv_data.dssdev = dssdev; + + ddata = &s_drv_data; + + mutex_init(&ddata->lock); + + dssdev->panel.config = OMAP_DSS_LCD_TFT; + dssdev->panel.timings.x_res = 800; + dssdev->panel.timings.y_res = 480; + dssdev->ctrl.pixel_size = 16; + dssdev->ctrl.rfbi_timings = n8x0_panel_timings; + + memset(&props, 0, sizeof(props)); + props.max_brightness = 127; + props.type = BACKLIGHT_PLATFORM; + bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev, + dssdev, &n8x0_bl_ops, &props); + if (IS_ERR(bldev)) { + r = PTR_ERR(bldev); + dev_err(&dssdev->dev, "register backlight failed\n"); + return r; + } + + ddata->bldev = bldev; + + bldev->props.fb_blank = FB_BLANK_UNBLANK; + bldev->props.power = FB_BLANK_UNBLANK; + bldev->props.brightness = 127; + + n8x0_bl_update_status(bldev); + + return 0; +} + +static void n8x0_panel_remove(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + struct backlight_device *bldev; + + dev_dbg(&dssdev->dev, "remove\n"); + + bldev = ddata->bldev; + bldev->props.power = FB_BLANK_POWERDOWN; + n8x0_bl_update_status(bldev); + backlight_device_unregister(bldev); + + dev_set_drvdata(&dssdev->dev, NULL); +} + +static int n8x0_panel_enable(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + int r; + + dev_dbg(&dssdev->dev, "enable\n"); + + mutex_lock(&ddata->lock); + + rfbi_bus_lock(); + + r = n8x0_panel_power_on(dssdev); + + rfbi_bus_unlock(); + + if (r) { + mutex_unlock(&ddata->lock); + return r; + } + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&ddata->lock); + + return 0; +} + +static void n8x0_panel_disable(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + + dev_dbg(&dssdev->dev, "disable\n"); + + mutex_lock(&ddata->lock); + + rfbi_bus_lock(); + + n8x0_panel_power_off(dssdev); + + rfbi_bus_unlock(); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&ddata->lock); +} + +static int n8x0_panel_suspend(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + + dev_dbg(&dssdev->dev, "suspend\n"); + + mutex_lock(&ddata->lock); + + rfbi_bus_lock(); + + n8x0_panel_power_off(dssdev); + + rfbi_bus_unlock(); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + + mutex_unlock(&ddata->lock); + + return 0; +} + +static int n8x0_panel_resume(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + int r; + + dev_dbg(&dssdev->dev, "resume\n"); + + mutex_lock(&ddata->lock); + + rfbi_bus_lock(); + + r = n8x0_panel_power_on(dssdev); + + rfbi_bus_unlock(); + + if (r) { + mutex_unlock(&ddata->lock); + return r; + } + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&ddata->lock); + + return 0; +} + +static void n8x0_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = dssdev->panel.timings; +} + +static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, + u16 *xres, u16 *yres) +{ + *xres = dssdev->panel.timings.x_res; + *yres = dssdev->panel.timings.y_res; +} + +static void update_done(void *data) +{ + rfbi_bus_unlock(); +} + +static int n8x0_panel_update(struct omap_dss_device *dssdev, + u16 x, u16 y, u16 w, u16 h) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + + dev_dbg(&dssdev->dev, "update\n"); + + mutex_lock(&ddata->lock); + rfbi_bus_lock(); + + omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h); + + blizzard_ctrl_setup_update(dssdev, x, y, w, h); + + omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL); + + mutex_unlock(&ddata->lock); + + return 0; +} + +static int n8x0_panel_sync(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *ddata = get_drv_data(dssdev); + + dev_dbg(&dssdev->dev, "sync\n"); + + mutex_lock(&ddata->lock); + rfbi_bus_lock(); + rfbi_bus_unlock(); + mutex_unlock(&ddata->lock); + + return 0; +} + +static struct omap_dss_driver n8x0_panel_driver = { + .probe = n8x0_panel_probe, + .remove = n8x0_panel_remove, + + .enable = n8x0_panel_enable, + .disable = n8x0_panel_disable, + .suspend = n8x0_panel_suspend, + .resume = n8x0_panel_resume, + + .update = n8x0_panel_update, + .sync = n8x0_panel_sync, + + .get_resolution = n8x0_panel_get_resolution, + .get_recommended_bpp = omapdss_default_get_recommended_bpp, + + .get_timings = n8x0_panel_get_timings, + + .driver = { + .name = "n8x0_panel", + .owner = THIS_MODULE, + }, +}; + +/* PANEL */ + +static int mipid_spi_probe(struct spi_device *spi) +{ + dev_dbg(&spi->dev, "mipid_spi_probe\n"); + + spi->mode = SPI_MODE_0; + + s_drv_data.spidev = spi; + + return 0; +} + +static int mipid_spi_remove(struct spi_device *spi) +{ + dev_dbg(&spi->dev, "mipid_spi_remove\n"); + return 0; +} + +static struct spi_driver mipid_spi_driver = { + .driver = { + .name = "lcd_mipid", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = mipid_spi_probe, + .remove = __devexit_p(mipid_spi_remove), +}; + +static int __init n8x0_panel_drv_init(void) +{ + int r; + + r = spi_register_driver(&mipid_spi_driver); + if (r) { + pr_err("n8x0_panel: spi driver registration failed\n"); + return r; + } + + r = omap_dss_register_driver(&n8x0_panel_driver); + if (r) { + pr_err("n8x0_panel: dss driver registration failed\n"); + spi_unregister_driver(&mipid_spi_driver); + return r; + } + + return 0; +} + +static void __exit n8x0_panel_drv_exit(void) +{ + spi_unregister_driver(&mipid_spi_driver); + + omap_dss_unregister_driver(&n8x0_panel_driver); +} + +module_init(n8x0_panel_drv_init); +module_exit(n8x0_panel_drv_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c new file mode 100644 index 0000000..98ebdad --- /dev/null +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -0,0 +1,594 @@ +/* + * picodlp panel driver + * picodlp_i2c_driver: i2c_client driver + * + * Copyright (C) 2009-2011 Texas Instruments + * Author: Mythri P K <mythripk@ti.com> + * Mayuresh Janorkar <mayur@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/input.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/gpio.h> + +#include <video/omapdss.h> +#include <video/omap-panel-picodlp.h> + +#include "panel-picodlp.h" + +struct picodlp_data { + struct mutex lock; + struct i2c_client *picodlp_i2c_client; +}; + +static struct i2c_board_info picodlp_i2c_board_info = { + I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b), +}; + +struct picodlp_i2c_data { + struct mutex xfer_lock; +}; + +static struct i2c_device_id picodlp_i2c_id[] = { + { "picodlp_i2c_driver", 0 }, +}; + +struct picodlp_i2c_command { + u8 reg; + u32 value; +}; + +static struct omap_video_timings pico_ls_timings = { + .x_res = 864, + .y_res = 480, + .hsw = 7, + .hfp = 11, + .hbp = 7, + + .pixel_clock = 19200, + + .vsw = 2, + .vfp = 3, + .vbp = 14, +}; + +static inline struct picodlp_panel_data + *get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct picodlp_panel_data *) dssdev->data; +} + +static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg) +{ + u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4]; + struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); + struct i2c_msg msg[2]; + + mutex_lock(&picodlp_i2c_data->xfer_lock); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = read_cmd; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 4; + msg[1].buf = data; + + i2c_transfer(client->adapter, msg, 2); + mutex_unlock(&picodlp_i2c_data->xfer_lock); + return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24)); +} + +static int picodlp_i2c_write_block(struct i2c_client *client, + u8 *data, int len) +{ + struct i2c_msg msg; + int i, r, msg_count = 1; + + struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); + + if (len < 1 || len > 32) { + dev_err(&client->dev, + "too long syn_write_block len %d\n", len); + return -EIO; + } + mutex_lock(&picodlp_i2c_data->xfer_lock); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + r = i2c_transfer(client->adapter, &msg, msg_count); + mutex_unlock(&picodlp_i2c_data->xfer_lock); + + /* + * i2c_transfer returns: + * number of messages sent in case of success + * a negative error number in case of failure + */ + if (r != msg_count) + goto err; + + /* In case of success */ + for (i = 0; i < len; i++) + dev_dbg(&client->dev, + "addr %x bw 0x%02x[%d]: 0x%02x\n", + client->addr, data[0] + i, i, data[i]); + + return 0; +err: + dev_err(&client->dev, "picodlp_i2c_write error\n"); + return r; +} + +static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value) +{ + u8 data[5]; + int i; + + data[0] = reg; + for (i = 1; i < 5; i++) + data[i] = (value >> (32 - (i) * 8)) & 0xFF; + + return picodlp_i2c_write_block(client, data, 5); +} + +static int picodlp_i2c_write_array(struct i2c_client *client, + const struct picodlp_i2c_command commands[], + int count) +{ + int i, r = 0; + for (i = 0; i < count; i++) { + r = picodlp_i2c_write(client, commands[i].reg, + commands[i].value); + if (r) + return r; + } + return r; +} + +static int picodlp_wait_for_dma_done(struct i2c_client *client) +{ + u8 trial = 100; + + do { + msleep(1); + if (!trial--) + return -ETIMEDOUT; + } while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS); + + return 0; +} + +/** + * picodlp_i2c_init: i2c_initialization routine + * client: i2c_client for communication + * + * return + * 0 : Success, no error + * error code : Failure + */ +static int picodlp_i2c_init(struct i2c_client *client) +{ + int r; + static const struct picodlp_i2c_command init_cmd_set1[] = { + {SOFT_RESET, 1}, + {DMD_PARK_TRIGGER, 1}, + {MISC_REG, 5}, + {SEQ_CONTROL, 0}, + {SEQ_VECTOR, 0x100}, + {DMD_BLOCK_COUNT, 7}, + {DMD_VCC_CONTROL, 0x109}, + {DMD_PARK_PULSE_COUNT, 0xA}, + {DMD_PARK_PULSE_WIDTH, 0xB}, + {DMD_PARK_DELAY, 0x2ED}, + {DMD_SHADOW_ENABLE, 0}, + {FLASH_OPCODE, 0xB}, + {FLASH_DUMMY_BYTES, 1}, + {FLASH_ADDR_BYTES, 3}, + {PBC_CONTROL, 0}, + {FLASH_START_ADDR, CMT_LUT_0_START_ADDR}, + {FLASH_READ_BYTES, CMT_LUT_0_SIZE}, + {CMT_SPLASH_LUT_START_ADDR, 0}, + {CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL}, + {PBC_CONTROL, 1}, + }; + + static const struct picodlp_i2c_command init_cmd_set2[] = { + {PBC_CONTROL, 0}, + {CMT_SPLASH_LUT_DEST_SELECT, 0}, + {PBC_CONTROL, 0}, + {FLASH_START_ADDR, SEQUENCE_0_START_ADDR}, + {FLASH_READ_BYTES, SEQUENCE_0_SIZE}, + {SEQ_RESET_LUT_START_ADDR, 0}, + {SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT}, + {PBC_CONTROL, 1}, + }; + + static const struct picodlp_i2c_command init_cmd_set3[] = { + {PBC_CONTROL, 0}, + {SEQ_RESET_LUT_DEST_SELECT, 0}, + {PBC_CONTROL, 0}, + {FLASH_START_ADDR, DRC_TABLE_0_START_ADDR}, + {FLASH_READ_BYTES, DRC_TABLE_0_SIZE}, + {SEQ_RESET_LUT_START_ADDR, 0}, + {SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL}, + {PBC_CONTROL, 1}, + }; + + static const struct picodlp_i2c_command init_cmd_set4[] = { + {PBC_CONTROL, 0}, + {SEQ_RESET_LUT_DEST_SELECT, 0}, + {SDC_ENABLE, 1}, + {AGC_CTRL, 7}, + {CCA_C1A, 0x100}, + {CCA_C1B, 0x0}, + {CCA_C1C, 0x0}, + {CCA_C2A, 0x0}, + {CCA_C2B, 0x100}, + {CCA_C2C, 0x0}, + {CCA_C3A, 0x0}, + {CCA_C3B, 0x0}, + {CCA_C3C, 0x100}, + {CCA_C7A, 0x100}, + {CCA_C7B, 0x100}, + {CCA_C7C, 0x100}, + {CCA_ENABLE, 1}, + {CPU_IF_MODE, 1}, + {SHORT_FLIP, 1}, + {CURTAIN_CONTROL, 0}, + {DMD_PARK_TRIGGER, 0}, + {R_DRIVE_CURRENT, 0x298}, + {G_DRIVE_CURRENT, 0x298}, + {B_DRIVE_CURRENT, 0x298}, + {RGB_DRIVER_ENABLE, 7}, + {SEQ_CONTROL, 0}, + {ACTGEN_CONTROL, 0x10}, + {SEQUENCE_MODE, SEQ_LOCK}, + {DATA_FORMAT, RGB888}, + {INPUT_RESOLUTION, WVGA_864_LANDSCAPE}, + {INPUT_SOURCE, PARALLEL_RGB}, + {CPU_IF_SYNC_METHOD, 1}, + {SEQ_CONTROL, 1} + }; + + r = picodlp_i2c_write_array(client, init_cmd_set1, + ARRAY_SIZE(init_cmd_set1)); + if (r) + return r; + + r = picodlp_wait_for_dma_done(client); + if (r) + return r; + + r = picodlp_i2c_write_array(client, init_cmd_set2, + ARRAY_SIZE(init_cmd_set2)); + if (r) + return r; + + r = picodlp_wait_for_dma_done(client); + if (r) + return r; + + r = picodlp_i2c_write_array(client, init_cmd_set3, + ARRAY_SIZE(init_cmd_set3)); + if (r) + return r; + + r = picodlp_wait_for_dma_done(client); + if (r) + return r; + + r = picodlp_i2c_write_array(client, init_cmd_set4, + ARRAY_SIZE(init_cmd_set4)); + if (r) + return r; + + return 0; +} + +static int picodlp_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct picodlp_i2c_data *picodlp_i2c_data; + + picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL); + + if (!picodlp_i2c_data) + return -ENOMEM; + + mutex_init(&picodlp_i2c_data->xfer_lock); + i2c_set_clientdata(client, picodlp_i2c_data); + + return 0; +} + +static int picodlp_i2c_remove(struct i2c_client *client) +{ + struct picodlp_i2c_data *picodlp_i2c_data = + i2c_get_clientdata(client); + kfree(picodlp_i2c_data); + return 0; +} + +static struct i2c_driver picodlp_i2c_driver = { + .driver = { + .name = "picodlp_i2c_driver", + }, + .probe = picodlp_i2c_probe, + .remove = picodlp_i2c_remove, + .id_table = picodlp_i2c_id, +}; + +static int picodlp_panel_power_on(struct omap_dss_device *dssdev) +{ + int r, trial = 100; + struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); + struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + return r; + } + + gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); + msleep(1); + gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); + + while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) { + if (!trial--) { + dev_err(&dssdev->dev, "emu_done signal not" + " going high\n"); + return -ETIMEDOUT; + } + msleep(5); + } + /* + * As per dpp2600 programming guide, + * it is required to sleep for 1000ms after emu_done signal goes high + * then only i2c commands can be successfully sent to dpp2600 + */ + msleep(1000); + r = omapdss_dpi_display_enable(dssdev); + if (r) { + dev_err(&dssdev->dev, "failed to enable DPI\n"); + goto err1; + } + + r = picodlp_i2c_init(picod->picodlp_i2c_client); + if (r) + goto err; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return r; +err: + omapdss_dpi_display_disable(dssdev); +err1: + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + + return r; +} + +static void picodlp_panel_power_off(struct omap_dss_device *dssdev) +{ + struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); + + omapdss_dpi_display_disable(dssdev); + + gpio_set_value(picodlp_pdata->emu_done_gpio, 0); + gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +} + +static int picodlp_panel_probe(struct omap_dss_device *dssdev) +{ + struct picodlp_data *picod; + struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); + struct i2c_adapter *adapter; + struct i2c_client *picodlp_i2c_client; + int r = 0, picodlp_adapter_id; + + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_ONOFF | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IVS; + dssdev->panel.acb = 0x0; + dssdev->panel.timings = pico_ls_timings; + + picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL); + if (!picod) + return -ENOMEM; + + mutex_init(&picod->lock); + + picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id; + + adapter = i2c_get_adapter(picodlp_adapter_id); + if (!adapter) { + dev_err(&dssdev->dev, "can't get i2c adapter\n"); + r = -ENODEV; + goto err; + } + + picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); + if (!picodlp_i2c_client) { + dev_err(&dssdev->dev, "can't add i2c device::" + " picodlp_i2c_client is NULL\n"); + r = -ENODEV; + goto err; + } + + picod->picodlp_i2c_client = picodlp_i2c_client; + + dev_set_drvdata(&dssdev->dev, picod); + return r; +err: + kfree(picod); + return r; +} + +static void picodlp_panel_remove(struct omap_dss_device *dssdev) +{ + struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); + + i2c_unregister_device(picod->picodlp_i2c_client); + dev_set_drvdata(&dssdev->dev, NULL); + dev_dbg(&dssdev->dev, "removing picodlp panel\n"); + + kfree(picod); +} + +static int picodlp_panel_enable(struct omap_dss_device *dssdev) +{ + struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); + int r; + + dev_dbg(&dssdev->dev, "enabling picodlp panel\n"); + + mutex_lock(&picod->lock); + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + mutex_unlock(&picod->lock); + return -EINVAL; + } + + r = picodlp_panel_power_on(dssdev); + mutex_unlock(&picod->lock); + + return r; +} + +static void picodlp_panel_disable(struct omap_dss_device *dssdev) +{ + struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&picod->lock); + /* Turn off DLP Power */ + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + picodlp_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + mutex_unlock(&picod->lock); + + dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); +} + +static int picodlp_panel_suspend(struct omap_dss_device *dssdev) +{ + struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&picod->lock); + /* Turn off DLP Power */ + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + mutex_unlock(&picod->lock); + dev_err(&dssdev->dev, "unable to suspend picodlp panel," + " panel is not ACTIVE\n"); + return -EINVAL; + } + + picodlp_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + mutex_unlock(&picod->lock); + + dev_dbg(&dssdev->dev, "suspending picodlp panel\n"); + return 0; +} + +static int picodlp_panel_resume(struct omap_dss_device *dssdev) +{ + struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&picod->lock); + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { + mutex_unlock(&picod->lock); + dev_err(&dssdev->dev, "unable to resume picodlp panel," + " panel is not ACTIVE\n"); + return -EINVAL; + } + + r = picodlp_panel_power_on(dssdev); + mutex_unlock(&picod->lock); + dev_dbg(&dssdev->dev, "resuming picodlp panel\n"); + return r; +} + +static void picodlp_get_resolution(struct omap_dss_device *dssdev, + u16 *xres, u16 *yres) +{ + *xres = dssdev->panel.timings.x_res; + *yres = dssdev->panel.timings.y_res; +} + +static struct omap_dss_driver picodlp_driver = { + .probe = picodlp_panel_probe, + .remove = picodlp_panel_remove, + + .enable = picodlp_panel_enable, + .disable = picodlp_panel_disable, + + .get_resolution = picodlp_get_resolution, + + .suspend = picodlp_panel_suspend, + .resume = picodlp_panel_resume, + + .driver = { + .name = "picodlp_panel", + .owner = THIS_MODULE, + }, +}; + +static int __init picodlp_init(void) +{ + int r = 0; + + r = i2c_add_driver(&picodlp_i2c_driver); + if (r) { + printk(KERN_WARNING "picodlp_i2c_driver" \ + " registration failed\n"); + return r; + } + + r = omap_dss_register_driver(&picodlp_driver); + if (r) + i2c_del_driver(&picodlp_i2c_driver); + + return r; +} + +static void __exit picodlp_exit(void) +{ + i2c_del_driver(&picodlp_i2c_driver); + omap_dss_unregister_driver(&picodlp_driver); +} + +module_init(picodlp_init); +module_exit(picodlp_exit); + +MODULE_AUTHOR("Mythri P K <mythripk@ti.com>"); +MODULE_DESCRIPTION("picodlp driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-picodlp.h b/drivers/video/omap2/displays/panel-picodlp.h new file mode 100644 index 0000000..a34b431 --- /dev/null +++ b/drivers/video/omap2/displays/panel-picodlp.h @@ -0,0 +1,288 @@ +/* + * Header file required by picodlp panel driver + * + * Copyright (C) 2009-2011 Texas Instruments + * Author: Mythri P K <mythripk@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/>. +*/ + +#ifndef __OMAP2_DISPLAY_PANEL_PICODLP_H +#define __OMAP2_DISPLAY_PANEL_PICODLP_H + +/* Commands used for configuring picodlp panel */ + +#define MAIN_STATUS 0x03 +#define PBC_CONTROL 0x08 +#define INPUT_SOURCE 0x0B +#define INPUT_RESOLUTION 0x0C +#define DATA_FORMAT 0x0D +#define IMG_ROTATION 0x0E +#define LONG_FLIP 0x0F +#define SHORT_FLIP 0x10 +#define TEST_PAT_SELECT 0x11 +#define R_DRIVE_CURRENT 0x12 +#define G_DRIVE_CURRENT 0x13 +#define B_DRIVE_CURRENT 0x14 +#define READ_REG_SELECT 0x15 +#define RGB_DRIVER_ENABLE 0x16 + +#define CPU_IF_MODE 0x18 +#define FRAME_RATE 0x19 +#define CPU_IF_SYNC_METHOD 0x1A +#define CPU_IF_SOF 0x1B +#define CPU_IF_EOF 0x1C +#define CPU_IF_SLEEP 0x1D + +#define SEQUENCE_MODE 0x1E +#define SOFT_RESET 0x1F +#define FRONT_END_RESET 0x21 +#define AUTO_PWR_ENABLE 0x22 + +#define VSYNC_LINE_DELAY 0x23 +#define CPU_PI_HORIZ_START 0x24 +#define CPU_PI_VERT_START 0x25 +#define CPU_PI_HORIZ_WIDTH 0x26 +#define CPU_PI_VERT_HEIGHT 0x27 + +#define PIXEL_MASK_CROP 0x28 +#define CROP_FIRST_LINE 0x29 +#define CROP_LAST_LINE 0x2A +#define CROP_FIRST_PIXEL 0x2B +#define CROP_LAST_PIXEL 0x2C +#define DMD_PARK_TRIGGER 0x2D + +#define MISC_REG 0x30 + +/* AGC registers */ +#define AGC_CTRL 0x50 +#define AGC_CLIPPED_PIXS 0x55 +#define AGC_BRIGHT_PIXS 0x56 +#define AGC_BG_PIXS 0x57 +#define AGC_SAFETY_MARGIN 0x17 + +/* Color Coordinate Adjustment registers */ +#define CCA_ENABLE 0x5E +#define CCA_C1A 0x5F +#define CCA_C1B 0x60 +#define CCA_C1C 0x61 +#define CCA_C2A 0x62 +#define CCA_C2B 0x63 +#define CCA_C2C 0x64 +#define CCA_C3A 0x65 +#define CCA_C3B 0x66 +#define CCA_C3C 0x67 +#define CCA_C7A 0x71 +#define CCA_C7B 0x72 +#define CCA_C7C 0x73 + +/** + * DLP Pico Processor 2600 comes with flash + * We can do DMA operations from flash for accessing Look Up Tables + */ +#define DMA_STATUS 0x100 +#define FLASH_ADDR_BYTES 0x74 +#define FLASH_DUMMY_BYTES 0x75 +#define FLASH_WRITE_BYTES 0x76 +#define FLASH_READ_BYTES 0x77 +#define FLASH_OPCODE 0x78 +#define FLASH_START_ADDR 0x79 +#define FLASH_DUMMY2 0x7A +#define FLASH_WRITE_DATA 0x7B + +#define TEMPORAL_DITH_DISABLE 0x7E +#define SEQ_CONTROL 0x82 +#define SEQ_VECTOR 0x83 + +/* DMD is Digital Micromirror Device */ +#define DMD_BLOCK_COUNT 0x84 +#define DMD_VCC_CONTROL 0x86 +#define DMD_PARK_PULSE_COUNT 0x87 +#define DMD_PARK_PULSE_WIDTH 0x88 +#define DMD_PARK_DELAY 0x89 +#define DMD_SHADOW_ENABLE 0x8E +#define SEQ_STATUS 0x8F +#define FLASH_CLOCK_CONTROL 0x98 +#define DMD_PARK 0x2D + +#define SDRAM_BIST_ENABLE 0x46 +#define DDR_DRIVER_STRENGTH 0x9A +#define SDC_ENABLE 0x9D +#define SDC_BUFF_SWAP_DISABLE 0xA3 +#define CURTAIN_CONTROL 0xA6 +#define DDR_BUS_SWAP_ENABLE 0xA7 +#define DMD_TRC_ENABLE 0xA8 +#define DMD_BUS_SWAP_ENABLE 0xA9 + +#define ACTGEN_ENABLE 0xAE +#define ACTGEN_CONTROL 0xAF +#define ACTGEN_HORIZ_BP 0xB0 +#define ACTGEN_VERT_BP 0xB1 + +/* Look Up Table access */ +#define CMT_SPLASH_LUT_START_ADDR 0xFA +#define CMT_SPLASH_LUT_DEST_SELECT 0xFB +#define CMT_SPLASH_LUT_DATA 0xFC +#define SEQ_RESET_LUT_START_ADDR 0xFD +#define SEQ_RESET_LUT_DEST_SELECT 0xFE +#define SEQ_RESET_LUT_DATA 0xFF + +/* Input source definitions */ +#define PARALLEL_RGB 0 +#define INT_TEST_PATTERN 1 +#define SPLASH_SCREEN 2 +#define CPU_INTF 3 +#define BT656 4 + +/* Standard input resolution definitions */ +#define QWVGA_LANDSCAPE 3 /* (427h*240v) */ +#define WVGA_864_LANDSCAPE 21 /* (864h*480v) */ +#define WVGA_DMD_OPTICAL_TEST 35 /* (608h*684v) */ + +/* Standard data format definitions */ +#define RGB565 0 +#define RGB666 1 +#define RGB888 2 + +/* Test Pattern definitions */ +#define TPG_CHECKERBOARD 0 +#define TPG_BLACK 1 +#define TPG_WHITE 2 +#define TPG_RED 3 +#define TPG_BLUE 4 +#define TPG_GREEN 5 +#define TPG_VLINES_BLACK 6 +#define TPG_HLINES_BLACK 7 +#define TPG_VLINES_ALT 8 +#define TPG_HLINES_ALT 9 +#define TPG_DIAG_LINES 10 +#define TPG_GREYRAMP_VERT 11 +#define TPG_GREYRAMP_HORIZ 12 +#define TPG_ANSI_CHECKERBOARD 13 + +/* sequence mode definitions */ +#define SEQ_FREE_RUN 0 +#define SEQ_LOCK 1 + +/* curtain color definitions */ +#define CURTAIN_BLACK 0 +#define CURTAIN_RED 1 +#define CURTAIN_GREEN 2 +#define CURTAIN_BLUE 3 +#define CURTAIN_YELLOW 4 +#define CURTAIN_MAGENTA 5 +#define CURTAIN_CYAN 6 +#define CURTAIN_WHITE 7 + +/* LUT definitions */ +#define CMT_LUT_NONE 0 +#define CMT_LUT_GREEN 1 +#define CMT_LUT_RED 2 +#define CMT_LUT_BLUE 3 +#define CMT_LUT_ALL 4 +#define SPLASH_LUT 5 + +#define SEQ_LUT_NONE 0 +#define SEQ_DRC_LUT_0 1 +#define SEQ_DRC_LUT_1 2 +#define SEQ_DRC_LUT_2 3 +#define SEQ_DRC_LUT_3 4 +#define SEQ_SEQ_LUT 5 +#define SEQ_DRC_LUT_ALL 6 +#define WPC_PROGRAM_LUT 7 + +#define BITSTREAM_START_ADDR 0x00000000 +#define BITSTREAM_SIZE 0x00040000 + +#define WPC_FW_0_START_ADDR 0x00040000 +#define WPC_FW_0_SIZE 0x00000ce8 + +#define SEQUENCE_0_START_ADDR 0x00044000 +#define SEQUENCE_0_SIZE 0x00001000 + +#define SEQUENCE_1_START_ADDR 0x00045000 +#define SEQUENCE_1_SIZE 0x00000d10 + +#define SEQUENCE_2_START_ADDR 0x00046000 +#define SEQUENCE_2_SIZE 0x00000d10 + +#define SEQUENCE_3_START_ADDR 0x00047000 +#define SEQUENCE_3_SIZE 0x00000d10 + +#define SEQUENCE_4_START_ADDR 0x00048000 +#define SEQUENCE_4_SIZE 0x00000d10 + +#define SEQUENCE_5_START_ADDR 0x00049000 +#define SEQUENCE_5_SIZE 0x00000d10 + +#define SEQUENCE_6_START_ADDR 0x0004a000 +#define SEQUENCE_6_SIZE 0x00000d10 + +#define CMT_LUT_0_START_ADDR 0x0004b200 +#define CMT_LUT_0_SIZE 0x00000600 + +#define CMT_LUT_1_START_ADDR 0x0004b800 +#define CMT_LUT_1_SIZE 0x00000600 + +#define CMT_LUT_2_START_ADDR 0x0004be00 +#define CMT_LUT_2_SIZE 0x00000600 + +#define CMT_LUT_3_START_ADDR 0x0004c400 +#define CMT_LUT_3_SIZE 0x00000600 + +#define CMT_LUT_4_START_ADDR 0x0004ca00 +#define CMT_LUT_4_SIZE 0x00000600 + +#define CMT_LUT_5_START_ADDR 0x0004d000 +#define CMT_LUT_5_SIZE 0x00000600 + +#define CMT_LUT_6_START_ADDR 0x0004d600 +#define CMT_LUT_6_SIZE 0x00000600 + +#define DRC_TABLE_0_START_ADDR 0x0004dc00 +#define DRC_TABLE_0_SIZE 0x00000100 + +#define SPLASH_0_START_ADDR 0x0004dd00 +#define SPLASH_0_SIZE 0x00032280 + +#define SEQUENCE_7_START_ADDR 0x00080000 +#define SEQUENCE_7_SIZE 0x00000d10 + +#define SEQUENCE_8_START_ADDR 0x00081800 +#define SEQUENCE_8_SIZE 0x00000d10 + +#define SEQUENCE_9_START_ADDR 0x00083000 +#define SEQUENCE_9_SIZE 0x00000d10 + +#define CMT_LUT_7_START_ADDR 0x0008e000 +#define CMT_LUT_7_SIZE 0x00000600 + +#define CMT_LUT_8_START_ADDR 0x0008e800 +#define CMT_LUT_8_SIZE 0x00000600 + +#define CMT_LUT_9_START_ADDR 0x0008f000 +#define CMT_LUT_9_SIZE 0x00000600 + +#define SPLASH_1_START_ADDR 0x0009a000 +#define SPLASH_1_SIZE 0x00032280 + +#define SPLASH_2_START_ADDR 0x000cd000 +#define SPLASH_2_SIZE 0x00032280 + +#define SPLASH_3_START_ADDR 0x00100000 +#define SPLASH_3_SIZE 0x00032280 + +#define OPT_SPLASH_0_START_ADDR 0x00134000 +#define OPT_SPLASH_0_SIZE 0x000cb100 + +#endif diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index ca00843..80c3f6a 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -35,26 +35,12 @@ #include <video/omapdss.h> #include <video/omap-panel-nokia-dsi.h> +#include <video/mipi_display.h> /* DSI Virtual channel. Hardcoded for now. */ #define TCH 0 #define DCS_READ_NUM_ERRORS 0x05 -#define DCS_READ_POWER_MODE 0x0a -#define DCS_READ_MADCTL 0x0b -#define DCS_READ_PIXEL_FORMAT 0x0c -#define DCS_RDDSDR 0x0f -#define DCS_SLEEP_IN 0x10 -#define DCS_SLEEP_OUT 0x11 -#define DCS_DISPLAY_OFF 0x28 -#define DCS_DISPLAY_ON 0x29 -#define DCS_COLUMN_ADDR 0x2a -#define DCS_PAGE_ADDR 0x2b -#define DCS_MEMORY_WRITE 0x2c -#define DCS_TEAR_OFF 0x34 -#define DCS_TEAR_ON 0x35 -#define DCS_MEM_ACC_CTRL 0x36 -#define DCS_PIXEL_FORMAT 0x3a #define DCS_BRIGHTNESS 0x51 #define DCS_CTRL_DISPLAY 0x53 #define DCS_WRITE_CABC 0x55 @@ -222,8 +208,6 @@ struct taal_data { struct delayed_work te_timeout_work; - bool use_dsi_bl; - bool cabc_broken; unsigned cabc_mode; @@ -302,7 +286,7 @@ static int taal_sleep_in(struct taal_data *td) hw_guard_wait(td); - cmd = DCS_SLEEP_IN; + cmd = MIPI_DCS_ENTER_SLEEP_MODE; r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1); if (r) return r; @@ -321,7 +305,7 @@ static int taal_sleep_out(struct taal_data *td) hw_guard_wait(td); - r = taal_dcs_write_0(td, DCS_SLEEP_OUT); + r = taal_dcs_write_0(td, MIPI_DCS_EXIT_SLEEP_MODE); if (r) return r; @@ -356,7 +340,7 @@ static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) u8 mode; int b5, b6, b7; - r = taal_dcs_read_1(td, DCS_READ_MADCTL, &mode); + r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode); if (r) return r; @@ -390,7 +374,7 @@ static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) mode &= ~((1<<7) | (1<<6) | (1<<5)); mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); - return taal_dcs_write_1(td, DCS_MEM_ACC_CTRL, mode); + return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode); } static int taal_set_update_window(struct taal_data *td, @@ -403,7 +387,7 @@ static int taal_set_update_window(struct taal_data *td, u16 y2 = y + h - 1; u8 buf[5]; - buf[0] = DCS_COLUMN_ADDR; + buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS; buf[1] = (x1 >> 8) & 0xff; buf[2] = (x1 >> 0) & 0xff; buf[3] = (x2 >> 8) & 0xff; @@ -413,7 +397,7 @@ static int taal_set_update_window(struct taal_data *td, if (r) return r; - buf[0] = DCS_PAGE_ADDR; + buf[0] = MIPI_DCS_SET_PAGE_ADDRESS; buf[1] = (y1 >> 8) & 0xff; buf[2] = (y1 >> 0) & 0xff; buf[3] = (y2 >> 8) & 0xff; @@ -555,7 +539,6 @@ static int taal_bl_update_status(struct backlight_device *dev) { struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; int level; @@ -569,23 +552,16 @@ static int taal_bl_update_status(struct backlight_device *dev) mutex_lock(&td->lock); - if (td->use_dsi_bl) { - if (td->enabled) { - dsi_bus_lock(dssdev); + if (td->enabled) { + dsi_bus_lock(dssdev); - r = taal_wake_up(dssdev); - if (!r) - r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level); + r = taal_wake_up(dssdev); + if (!r) + r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level); - dsi_bus_unlock(dssdev); - } else { - r = 0; - } + dsi_bus_unlock(dssdev); } else { - if (!panel_data->set_backlight) - r = -EINVAL; - else - r = panel_data->set_backlight(dssdev, level); + r = 0; } mutex_unlock(&td->lock); @@ -964,7 +940,7 @@ static int taal_probe(struct omap_dss_device *dssdev) { struct backlight_properties props; struct taal_data *td; - struct backlight_device *bldev; + struct backlight_device *bldev = NULL; struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); struct panel_config *panel_config = NULL; int r, i; @@ -990,7 +966,7 @@ static int taal_probe(struct omap_dss_device *dssdev) dssdev->panel.config = OMAP_DSS_LCD_TFT; dssdev->panel.timings = panel_config->timings; - dssdev->ctrl.pixel_size = 24; + dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; td = kzalloc(sizeof(*td), GFP_KERNEL); if (!td) { @@ -1025,35 +1001,26 @@ static int taal_probe(struct omap_dss_device *dssdev) taal_hw_reset(dssdev); - /* if no platform set_backlight() defined, presume DSI backlight - * control */ - memset(&props, 0, sizeof(struct backlight_properties)); - if (!panel_data->set_backlight) - td->use_dsi_bl = true; - - if (td->use_dsi_bl) + if (panel_data->use_dsi_backlight) { + memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 255; - else - props.max_brightness = 127; - - props.type = BACKLIGHT_RAW; - bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev, - dssdev, &taal_bl_ops, &props); - if (IS_ERR(bldev)) { - r = PTR_ERR(bldev); - goto err_bl; - } - td->bldev = bldev; + props.type = BACKLIGHT_RAW; + bldev = backlight_device_register(dev_name(&dssdev->dev), + &dssdev->dev, dssdev, &taal_bl_ops, &props); + if (IS_ERR(bldev)) { + r = PTR_ERR(bldev); + goto err_bl; + } + + td->bldev = bldev; - bldev->props.fb_blank = FB_BLANK_UNBLANK; - bldev->props.power = FB_BLANK_UNBLANK; - if (td->use_dsi_bl) + bldev->props.fb_blank = FB_BLANK_UNBLANK; + bldev->props.power = FB_BLANK_UNBLANK; bldev->props.brightness = 255; - else - bldev->props.brightness = 127; - taal_bl_update_status(bldev); + taal_bl_update_status(bldev); + } if (panel_data->use_ext_te) { int gpio = panel_data->ext_te_gpio; @@ -1111,7 +1078,8 @@ err_irq: if (panel_data->use_ext_te) gpio_free(panel_data->ext_te_gpio); err_gpio: - backlight_device_unregister(bldev); + if (bldev != NULL) + backlight_device_unregister(bldev); err_bl: destroy_workqueue(td->workqueue); err_wq: @@ -1140,9 +1108,11 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) } bldev = td->bldev; - bldev->props.power = FB_BLANK_POWERDOWN; - taal_bl_update_status(bldev); - backlight_device_unregister(bldev); + if (bldev != NULL) { + bldev->props.power = FB_BLANK_POWERDOWN; + taal_bl_update_status(bldev); + backlight_device_unregister(bldev); + } taal_cancel_ulps_work(dssdev); taal_cancel_esd_work(dssdev); @@ -1195,7 +1165,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; - r = taal_dcs_write_1(td, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ + r = taal_dcs_write_1(td, MIPI_DCS_SET_PIXEL_FORMAT, + MIPI_DCS_PIXEL_FMT_24BIT); if (r) goto err; @@ -1209,7 +1180,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) goto err; } - r = taal_dcs_write_0(td, DCS_DISPLAY_ON); + r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_ON); if (r) goto err; @@ -1246,7 +1217,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; - r = taal_dcs_write_0(td, DCS_DISPLAY_OFF); + r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); if (!r) r = taal_sleep_in(td); @@ -1529,9 +1500,9 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) int r; if (enable) - r = taal_dcs_write_1(td, DCS_TEAR_ON, 0); + r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); else - r = taal_dcs_write_0(td, DCS_TEAR_OFF); + r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF); if (!panel_data->use_ext_te) omapdss_dsi_enable_te(dssdev, enable); @@ -1851,7 +1822,7 @@ static void taal_esd_work(struct work_struct *work) goto err; } - r = taal_dcs_read_1(td, DCS_RDDSDR, &state1); + r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1); if (r) { dev_err(&dssdev->dev, "failed to read Taal status\n"); goto err; @@ -1864,7 +1835,7 @@ static void taal_esd_work(struct work_struct *work) goto err; } - r = taal_dcs_read_1(td, DCS_RDDSDR, &state2); + r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2); if (r) { dev_err(&dssdev->dev, "failed to read Taal status\n"); goto err; @@ -1880,7 +1851,7 @@ static void taal_esd_work(struct work_struct *work) /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ if (td->te_enabled && panel_data->use_ext_te) { - r = taal_dcs_write_1(td, DCS_TEAR_ON, 0); + r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); if (r) goto err; } diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 0d12524..7be7c06 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -1,5 +1,5 @@ menuconfig OMAP2_DSS - tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)" + tristate "OMAP2+ Display Subsystem support" depends on ARCH_OMAP2PLUS help OMAP2+ Display Subsystem support. diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 10d9d3b..bd34ac5 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -6,4 +6,4 @@ omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ - hdmi_omap4_panel.o + hdmi_panel.o ti_hdmi_4xxx_ip.o diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 76821fe..86ec12e 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -145,6 +145,10 @@ static int dss_initialize_debugfs(void) debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir, &venc_dump_regs, &dss_debug_fops); #endif +#ifdef CONFIG_OMAP4_DSS_HDMI + debugfs_create_file("hdmi", S_IRUGO, dss_debugfs_dir, + &hdmi_dump_regs, &dss_debug_fops); +#endif return 0; } diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 0f3961a..6892cfd 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -106,7 +106,7 @@ static struct { int irq; struct clk *dss_clk; - u32 fifo_size[3]; + u32 fifo_size[MAX_DSS_OVERLAYS]; spinlock_t irq_lock; u32 irq_error_mask; @@ -171,172 +171,98 @@ static int dispc_get_ctx_loss_count(void) static void dispc_save_context(void) { - int i; + int i, j; DSSDBG("dispc_save_context\n"); SR(IRQENABLE); SR(CONTROL); SR(CONFIG); - SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD)); - SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT)); - SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD)); - SR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT)); SR(LINE_NUMBER); - SR(TIMING_H(OMAP_DSS_CHANNEL_LCD)); - SR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); - SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); - SR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || + dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) SR(GLOBAL_ALPHA); - SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); - SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { SR(CONTROL2); - SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2)); - SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2)); - SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2)); - SR(TIMING_H(OMAP_DSS_CHANNEL_LCD2)); - SR(TIMING_V(OMAP_DSS_CHANNEL_LCD2)); - SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2)); - SR(DIVISORo(OMAP_DSS_CHANNEL_LCD2)); SR(CONFIG2); } - SR(OVL_BA0(OMAP_DSS_GFX)); - SR(OVL_BA1(OMAP_DSS_GFX)); - SR(OVL_POSITION(OMAP_DSS_GFX)); - SR(OVL_SIZE(OMAP_DSS_GFX)); - SR(OVL_ATTRIBUTES(OMAP_DSS_GFX)); - SR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX)); - SR(OVL_ROW_INC(OMAP_DSS_GFX)); - SR(OVL_PIXEL_INC(OMAP_DSS_GFX)); - SR(OVL_WINDOW_SKIP(OMAP_DSS_GFX)); - SR(OVL_TABLE_BA(OMAP_DSS_GFX)); + for (i = 0; i < dss_feat_get_num_mgrs(); i++) { + SR(DEFAULT_COLOR(i)); + SR(TRANS_COLOR(i)); + SR(SIZE_MGR(i)); + if (i == OMAP_DSS_CHANNEL_DIGIT) + continue; + SR(TIMING_H(i)); + SR(TIMING_V(i)); + SR(POL_FREQ(i)); + SR(DIVISORo(i)); - SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD)); - SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); - SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); + SR(DATA_CYCLE1(i)); + SR(DATA_CYCLE2(i)); + SR(DATA_CYCLE3(i)); - if (dss_has_feature(FEAT_CPR)) { - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); - } - if (dss_has_feature(FEAT_MGR_LCD2)) { if (dss_has_feature(FEAT_CPR)) { - SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + SR(CPR_COEF_R(i)); + SR(CPR_COEF_G(i)); + SR(CPR_COEF_B(i)); } - - SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); - SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); - SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); } - if (dss_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(OMAP_DSS_GFX)); - - /* VID1 */ - SR(OVL_BA0(OMAP_DSS_VIDEO1)); - SR(OVL_BA1(OMAP_DSS_VIDEO1)); - SR(OVL_POSITION(OMAP_DSS_VIDEO1)); - SR(OVL_SIZE(OMAP_DSS_VIDEO1)); - SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); - SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); - SR(OVL_ROW_INC(OMAP_DSS_VIDEO1)); - SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); - SR(OVL_FIR(OMAP_DSS_VIDEO1)); - SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU0(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU1(OMAP_DSS_VIDEO1)); - - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 5; i++) - SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); - } - - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); - SR(OVL_BA1_UV(OMAP_DSS_VIDEO1)); - SR(OVL_FIR2(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1)); - SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1)); - - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i)); - } - if (dss_has_feature(FEAT_ATTR2)) - SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - - if (dss_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); - - /* VID2 */ - SR(OVL_BA0(OMAP_DSS_VIDEO2)); - SR(OVL_BA1(OMAP_DSS_VIDEO2)); - SR(OVL_POSITION(OMAP_DSS_VIDEO2)); - SR(OVL_SIZE(OMAP_DSS_VIDEO2)); - SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); - SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); - SR(OVL_ROW_INC(OMAP_DSS_VIDEO2)); - SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); - SR(OVL_FIR(OMAP_DSS_VIDEO2)); - SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU0(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU1(OMAP_DSS_VIDEO2)); + for (i = 0; i < dss_feat_get_num_ovls(); i++) { + SR(OVL_BA0(i)); + SR(OVL_BA1(i)); + SR(OVL_POSITION(i)); + SR(OVL_SIZE(i)); + SR(OVL_ATTRIBUTES(i)); + SR(OVL_FIFO_THRESHOLD(i)); + SR(OVL_ROW_INC(i)); + SR(OVL_PIXEL_INC(i)); + if (dss_has_feature(FEAT_PRELOAD)) + SR(OVL_PRELOAD(i)); + if (i == OMAP_DSS_GFX) { + SR(OVL_WINDOW_SKIP(i)); + SR(OVL_TABLE_BA(i)); + continue; + } + SR(OVL_FIR(i)); + SR(OVL_PICTURE_SIZE(i)); + SR(OVL_ACCU0(i)); + SR(OVL_ACCU1(i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + SR(OVL_FIR_COEF_H(i, j)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + SR(OVL_FIR_COEF_HV(i, j)); - for (i = 0; i < 5; i++) - SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 5; j++) + SR(OVL_CONV_COEF(i, j)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); - } + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (j = 0; j < 8; j++) + SR(OVL_FIR_COEF_V(i, j)); + } - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); - SR(OVL_BA1_UV(OMAP_DSS_VIDEO2)); - SR(OVL_FIR2(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2)); - SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + SR(OVL_BA0_UV(i)); + SR(OVL_BA1_UV(i)); + SR(OVL_FIR2(i)); + SR(OVL_ACCU2_0(i)); + SR(OVL_ACCU2_1(i)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + SR(OVL_FIR_COEF_H2(i, j)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + SR(OVL_FIR_COEF_HV2(i, j)); - for (i = 0; i < 8; i++) - SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + SR(OVL_FIR_COEF_V2(i, j)); + } + if (dss_has_feature(FEAT_ATTR2)) + SR(OVL_ATTRIBUTES2(i)); } - if (dss_has_feature(FEAT_ATTR2)) - SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - - if (dss_has_feature(FEAT_PRELOAD)) - SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) SR(DIVISOR); @@ -349,7 +275,7 @@ static void dispc_save_context(void) static void dispc_restore_context(void) { - int i, ctx; + int i, j, ctx; DSSDBG("dispc_restore_context\n"); @@ -367,165 +293,89 @@ static void dispc_restore_context(void) /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); - RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD)); - RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT)); - RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD)); - RR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT)); RR(LINE_NUMBER); - RR(TIMING_H(OMAP_DSS_CHANNEL_LCD)); - RR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); - RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); - RR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || + dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) RR(GLOBAL_ALPHA); - RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); - RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_MGR_LCD2)) { - RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2)); - RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2)); - RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2)); - RR(TIMING_H(OMAP_DSS_CHANNEL_LCD2)); - RR(TIMING_V(OMAP_DSS_CHANNEL_LCD2)); - RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2)); - RR(DIVISORo(OMAP_DSS_CHANNEL_LCD2)); + if (dss_has_feature(FEAT_MGR_LCD2)) RR(CONFIG2); - } - - RR(OVL_BA0(OMAP_DSS_GFX)); - RR(OVL_BA1(OMAP_DSS_GFX)); - RR(OVL_POSITION(OMAP_DSS_GFX)); - RR(OVL_SIZE(OMAP_DSS_GFX)); - RR(OVL_ATTRIBUTES(OMAP_DSS_GFX)); - RR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX)); - RR(OVL_ROW_INC(OMAP_DSS_GFX)); - RR(OVL_PIXEL_INC(OMAP_DSS_GFX)); - RR(OVL_WINDOW_SKIP(OMAP_DSS_GFX)); - RR(OVL_TABLE_BA(OMAP_DSS_GFX)); - - RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD)); - RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); - RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); + for (i = 0; i < dss_feat_get_num_mgrs(); i++) { + RR(DEFAULT_COLOR(i)); + RR(TRANS_COLOR(i)); + RR(SIZE_MGR(i)); + if (i == OMAP_DSS_CHANNEL_DIGIT) + continue; + RR(TIMING_H(i)); + RR(TIMING_V(i)); + RR(POL_FREQ(i)); + RR(DIVISORo(i)); - if (dss_has_feature(FEAT_CPR)) { - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); - } - if (dss_has_feature(FEAT_MGR_LCD2)) { - RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); - RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); - RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); + RR(DATA_CYCLE1(i)); + RR(DATA_CYCLE2(i)); + RR(DATA_CYCLE3(i)); if (dss_has_feature(FEAT_CPR)) { - RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); + RR(CPR_COEF_R(i)); + RR(CPR_COEF_G(i)); + RR(CPR_COEF_B(i)); } } - if (dss_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(OMAP_DSS_GFX)); - - /* VID1 */ - RR(OVL_BA0(OMAP_DSS_VIDEO1)); - RR(OVL_BA1(OMAP_DSS_VIDEO1)); - RR(OVL_POSITION(OMAP_DSS_VIDEO1)); - RR(OVL_SIZE(OMAP_DSS_VIDEO1)); - RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); - RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); - RR(OVL_ROW_INC(OMAP_DSS_VIDEO1)); - RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); - RR(OVL_FIR(OMAP_DSS_VIDEO1)); - RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU0(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU1(OMAP_DSS_VIDEO1)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 5; i++) - RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); - - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); - } - - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - RR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); - RR(OVL_BA1_UV(OMAP_DSS_VIDEO1)); - RR(OVL_FIR2(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1)); - RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i)); - - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i)); - } - if (dss_has_feature(FEAT_ATTR2)) - RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - - if (dss_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); - - /* VID2 */ - RR(OVL_BA0(OMAP_DSS_VIDEO2)); - RR(OVL_BA1(OMAP_DSS_VIDEO2)); - RR(OVL_POSITION(OMAP_DSS_VIDEO2)); - RR(OVL_SIZE(OMAP_DSS_VIDEO2)); - RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); - RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); - RR(OVL_ROW_INC(OMAP_DSS_VIDEO2)); - RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); - RR(OVL_FIR(OMAP_DSS_VIDEO2)); - RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU0(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU1(OMAP_DSS_VIDEO2)); + for (i = 0; i < dss_feat_get_num_ovls(); i++) { + RR(OVL_BA0(i)); + RR(OVL_BA1(i)); + RR(OVL_POSITION(i)); + RR(OVL_SIZE(i)); + RR(OVL_ATTRIBUTES(i)); + RR(OVL_FIFO_THRESHOLD(i)); + RR(OVL_ROW_INC(i)); + RR(OVL_PIXEL_INC(i)); + if (dss_has_feature(FEAT_PRELOAD)) + RR(OVL_PRELOAD(i)); + if (i == OMAP_DSS_GFX) { + RR(OVL_WINDOW_SKIP(i)); + RR(OVL_TABLE_BA(i)); + continue; + } + RR(OVL_FIR(i)); + RR(OVL_PICTURE_SIZE(i)); + RR(OVL_ACCU0(i)); + RR(OVL_ACCU1(i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + RR(OVL_FIR_COEF_H(i, j)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + RR(OVL_FIR_COEF_HV(i, j)); - for (i = 0; i < 5; i++) - RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 5; j++) + RR(OVL_CONV_COEF(i, j)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); - } + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (j = 0; j < 8; j++) + RR(OVL_FIR_COEF_V(i, j)); + } - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - RR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); - RR(OVL_BA1_UV(OMAP_DSS_VIDEO2)); - RR(OVL_FIR2(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2)); - RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2)); + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + RR(OVL_BA0_UV(i)); + RR(OVL_BA1_UV(i)); + RR(OVL_FIR2(i)); + RR(OVL_ACCU2_0(i)); + RR(OVL_ACCU2_1(i)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + RR(OVL_FIR_COEF_H2(i, j)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + RR(OVL_FIR_COEF_HV2(i, j)); - for (i = 0; i < 8; i++) - RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i)); + for (j = 0; j < 8; j++) + RR(OVL_FIR_COEF_V2(i, j)); + } + if (dss_has_feature(FEAT_ATTR2)) + RR(OVL_ATTRIBUTES2(i)); } - if (dss_has_feature(FEAT_ATTR2)) - RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - - if (dss_has_feature(FEAT_PRELOAD)) - RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); if (dss_has_feature(FEAT_CORE_CLK_DIV)) RR(DIVISOR); @@ -570,13 +420,28 @@ void dispc_runtime_put(void) WARN_ON(r < 0); } +static inline bool dispc_mgr_is_lcd(enum omap_channel channel) +{ + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) + return true; + else + return false; +} + +static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel) +{ + struct omap_overlay_manager *mgr = + omap_dss_get_overlay_manager(channel); -bool dispc_go_busy(enum omap_channel channel) + return mgr ? mgr->device : NULL; +} + +bool dispc_mgr_go_busy(enum omap_channel channel) { int bit; - if (channel == OMAP_DSS_CHANNEL_LCD || - channel == OMAP_DSS_CHANNEL_LCD2) + if (dispc_mgr_is_lcd(channel)) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ @@ -587,13 +452,12 @@ bool dispc_go_busy(enum omap_channel channel) return REG_GET(DISPC_CONTROL, bit, bit) == 1; } -void dispc_go(enum omap_channel channel) +void dispc_mgr_go(enum omap_channel channel) { int bit; bool enable_bit, go_bit; - if (channel == OMAP_DSS_CHANNEL_LCD || - channel == OMAP_DSS_CHANNEL_LCD2) + if (dispc_mgr_is_lcd(channel)) bit = 0; /* LCDENABLE */ else bit = 1; /* DIGITALENABLE */ @@ -607,8 +471,7 @@ void dispc_go(enum omap_channel channel) if (!enable_bit) return; - if (channel == OMAP_DSS_CHANNEL_LCD || - channel == OMAP_DSS_CHANNEL_LCD2) + if (dispc_mgr_is_lcd(channel)) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ @@ -632,43 +495,44 @@ void dispc_go(enum omap_channel channel) REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); } -static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) +static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) { dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); } -static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value) +static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value) { dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value); } -static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value) +static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value) { dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value); } -static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value) +static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value) { BUG_ON(plane == OMAP_DSS_GFX); dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value); } -static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value) +static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg, + u32 value) { BUG_ON(plane == OMAP_DSS_GFX); dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value); } -static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value) +static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) { BUG_ON(plane == OMAP_DSS_GFX); dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); } -static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, +static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, int vscaleup, int five_taps, enum omap_color_component color_comp) { @@ -769,11 +633,11 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, | FLD_VAL(v_coef[i].vc2, 31, 24); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { - _dispc_write_firh_reg(plane, i, h); - _dispc_write_firhv_reg(plane, i, hv); + dispc_ovl_write_firh_reg(plane, i, h); + dispc_ovl_write_firhv_reg(plane, i, hv); } else { - _dispc_write_firh2_reg(plane, i, h); - _dispc_write_firhv2_reg(plane, i, hv); + dispc_ovl_write_firh2_reg(plane, i, h); + dispc_ovl_write_firhv2_reg(plane, i, hv); } } @@ -784,15 +648,16 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, v = FLD_VAL(v_coef[i].vc00, 7, 0) | FLD_VAL(v_coef[i].vc22, 15, 8); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) - _dispc_write_firv_reg(plane, i, v); + dispc_ovl_write_firv_reg(plane, i, v); else - _dispc_write_firv2_reg(plane, i, v); + dispc_ovl_write_firv2_reg(plane, i, v); } } } static void _dispc_setup_color_conv_coef(void) { + int i; const struct color_conv_coef { int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; int full_range; @@ -806,65 +671,54 @@ static void _dispc_setup_color_conv_coef(void) ct = &ctbl_bt601_5; - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4), - CVAL(0, ct->bcb)); - - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4), - CVAL(0, ct->bcb)); + for (i = 1; i < dss_feat_get_num_ovls(); i++) { + dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), + CVAL(ct->rcr, ct->ry)); + dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), + CVAL(ct->gy, ct->rcb)); + dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), + CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), + CVAL(ct->bcr, ct->by)); + dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), + CVAL(0, ct->bcb)); -#undef CVAL + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, + 11, 11); + } - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1), - ct->full_range, 11, 11); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2), - ct->full_range, 11, 11); +#undef CVAL } -static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr) +static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) { dispc_write_reg(DISPC_OVL_BA0(plane), paddr); } -static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr) +static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr) { dispc_write_reg(DISPC_OVL_BA1(plane), paddr); } -static void _dispc_set_plane_ba0_uv(enum omap_plane plane, u32 paddr) +static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr) { dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr); } -static void _dispc_set_plane_ba1_uv(enum omap_plane plane, u32 paddr) +static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) { dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); } -static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y) +static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) { u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); dispc_write_reg(DISPC_OVL_POSITION(plane), val); } -static void _dispc_set_pic_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) { u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); @@ -874,7 +728,7 @@ static void _dispc_set_pic_size(enum omap_plane plane, int width, int height) dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); } -static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) { u32 val; @@ -885,44 +739,61 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) dispc_write_reg(DISPC_OVL_SIZE(plane), val); } -static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable) +static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) { - if (!dss_has_feature(FEAT_PRE_MULT_ALPHA)) + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + + if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) return; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); +} + +static void dispc_ovl_enable_zorder_planes(void) +{ + int i; + + if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) return; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); + for (i = 0; i < dss_feat_get_num_ovls(); i++) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } -static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) +static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) { - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + + if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) return; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); +} + +static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) +{ + static const unsigned shifts[] = { 0, 8, 16, 24, }; + int shift; + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) return; - if (plane == OMAP_DSS_GFX) - REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); - else if (plane == OMAP_DSS_VIDEO2) - REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16); + shift = shifts[plane]; + REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); } -static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc) +static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc) { dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc); } -static void _dispc_set_row_inc(enum omap_plane plane, s32 inc) +static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc) { dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc); } -static void _dispc_set_color_mode(enum omap_plane plane, +static void dispc_ovl_set_color_mode(enum omap_plane plane, enum omap_color_mode color_mode) { u32 m = 0; @@ -1003,7 +874,7 @@ static void _dispc_set_color_mode(enum omap_plane plane, REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } -void dispc_set_channel_out(enum omap_plane plane, +static void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) { int shift; @@ -1016,6 +887,7 @@ void dispc_set_channel_out(enum omap_plane plane, break; case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: shift = 16; break; default: @@ -1050,24 +922,13 @@ void dispc_set_channel_out(enum omap_plane plane, dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } -static void dispc_set_burst_size(enum omap_plane plane, +static void dispc_ovl_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { + static const unsigned shifts[] = { 6, 14, 14, 14, }; int shift; - switch (plane) { - case OMAP_DSS_GFX: - shift = 6; - break; - case OMAP_DSS_VIDEO1: - case OMAP_DSS_VIDEO2: - shift = 14; - break; - default: - BUG(); - return; - } - + shift = shifts[plane]; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); } @@ -1078,10 +939,10 @@ static void dispc_configure_burst_sizes(void) /* Configure burst size always to maximum size */ for (i = 0; i < omap_dss_get_num_overlays(); ++i) - dispc_set_burst_size(i, burst_size); + dispc_ovl_set_burst_size(i, burst_size); } -u32 dispc_get_burst_size(enum omap_plane plane) +u32 dispc_ovl_get_burst_size(enum omap_plane plane) { unsigned unit = dss_feat_get_burst_size_unit(); /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ @@ -1102,7 +963,7 @@ void dispc_enable_gamma_table(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); } -void dispc_enable_cpr(enum omap_channel channel, bool enable) +void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) { u16 reg; @@ -1116,12 +977,12 @@ void dispc_enable_cpr(enum omap_channel channel, bool enable) REG_FLD_MOD(reg, enable, 15, 15); } -void dispc_set_cpr_coef(enum omap_channel channel, +void dispc_mgr_set_cpr_coef(enum omap_channel channel, struct omap_dss_cpr_coefs *coefs) { u32 coef_r, coef_g, coef_b; - if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2) + if (!dispc_mgr_is_lcd(channel)) return; coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | @@ -1136,7 +997,7 @@ void dispc_set_cpr_coef(enum omap_channel channel, dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); } -static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) +static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) { u32 val; @@ -1147,19 +1008,16 @@ static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } -void dispc_enable_replication(enum omap_plane plane, bool enable) +static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) { - int bit; - - if (plane == OMAP_DSS_GFX) - bit = 5; - else - bit = 10; + static const unsigned shifts[] = { 5, 10, 10, 10 }; + int shift; - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); + shift = shifts[plane]; + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); } -void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) +void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height) { u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); @@ -1186,19 +1044,20 @@ static void dispc_read_plane_fifo_sizes(void) dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); - for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { + for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); size *= unit; dispc.fifo_size[plane] = size; } } -u32 dispc_get_plane_fifo_size(enum omap_plane plane) +u32 dispc_ovl_get_fifo_size(enum omap_plane plane) { return dispc.fifo_size[plane]; } -void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) +static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, + u32 high) { u8 hi_start, hi_end, lo_start, lo_end; u32 unit; @@ -1233,7 +1092,7 @@ void dispc_enable_fifomerge(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); } -static void _dispc_set_fir(enum omap_plane plane, +static void dispc_ovl_set_fir(enum omap_plane plane, int hinc, int vinc, enum omap_color_component color_comp) { @@ -1256,7 +1115,7 @@ static void _dispc_set_fir(enum omap_plane plane, } } -static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) +static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) { u32 val; u8 hor_start, hor_end, vert_start, vert_end; @@ -1270,7 +1129,7 @@ static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) dispc_write_reg(DISPC_OVL_ACCU0(plane), val); } -static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) +static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) { u32 val; u8 hor_start, hor_end, vert_start, vert_end; @@ -1284,7 +1143,8 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) dispc_write_reg(DISPC_OVL_ACCU1(plane), val); } -static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu) +static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu, + int vaccu) { u32 val; @@ -1292,7 +1152,8 @@ static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu) dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val); } -static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu) +static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu, + int vaccu) { u32 val; @@ -1300,7 +1161,7 @@ static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu) dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val); } -static void _dispc_set_scale_param(enum omap_plane plane, +static void dispc_ovl_set_scale_param(enum omap_plane plane, u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, bool five_taps, u8 rotation, @@ -1312,15 +1173,16 @@ static void _dispc_set_scale_param(enum omap_plane plane, hscaleup = orig_width <= out_width; vscaleup = orig_height <= out_height; - _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps, color_comp); + dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps, + color_comp); fir_hinc = 1024 * orig_width / out_width; fir_vinc = 1024 * orig_height / out_height; - _dispc_set_fir(plane, fir_hinc, fir_vinc, color_comp); + dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); } -static void _dispc_set_scaling_common(enum omap_plane plane, +static void dispc_ovl_set_scaling_common(enum omap_plane plane, u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, bool ilace, bool five_taps, @@ -1331,7 +1193,7 @@ static void _dispc_set_scaling_common(enum omap_plane plane, int accu1 = 0; u32 l; - _dispc_set_scale_param(plane, orig_width, orig_height, + dispc_ovl_set_scale_param(plane, orig_width, orig_height, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_RGB_Y); l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); @@ -1370,11 +1232,11 @@ static void _dispc_set_scaling_common(enum omap_plane plane, } } - _dispc_set_vid_accu0(plane, 0, accu0); - _dispc_set_vid_accu1(plane, 0, accu1); + dispc_ovl_set_vid_accu0(plane, 0, accu0); + dispc_ovl_set_vid_accu1(plane, 0, accu1); } -static void _dispc_set_scaling_uv(enum omap_plane plane, +static void dispc_ovl_set_scaling_uv(enum omap_plane plane, u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, bool ilace, bool five_taps, @@ -1422,7 +1284,7 @@ static void _dispc_set_scaling_uv(enum omap_plane plane, if (out_height != orig_height) scale_y = true; - _dispc_set_scale_param(plane, orig_width, orig_height, + dispc_ovl_set_scale_param(plane, orig_width, orig_height, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_UV); @@ -1433,11 +1295,11 @@ static void _dispc_set_scaling_uv(enum omap_plane plane, /* set V scaling */ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); - _dispc_set_vid_accu2_0(plane, 0x80, 0); - _dispc_set_vid_accu2_1(plane, 0x80, 0); + dispc_ovl_set_vid_accu2_0(plane, 0x80, 0); + dispc_ovl_set_vid_accu2_1(plane, 0x80, 0); } -static void _dispc_set_scaling(enum omap_plane plane, +static void dispc_ovl_set_scaling(enum omap_plane plane, u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, bool ilace, bool five_taps, @@ -1446,14 +1308,14 @@ static void _dispc_set_scaling(enum omap_plane plane, { BUG_ON(plane == OMAP_DSS_GFX); - _dispc_set_scaling_common(plane, + dispc_ovl_set_scaling_common(plane, orig_width, orig_height, out_width, out_height, ilace, five_taps, fieldmode, color_mode, rotation); - _dispc_set_scaling_uv(plane, + dispc_ovl_set_scaling_uv(plane, orig_width, orig_height, out_width, out_height, ilace, five_taps, @@ -1461,7 +1323,7 @@ static void _dispc_set_scaling(enum omap_plane plane, rotation); } -static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, +static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, bool mirroring, enum omap_color_mode color_mode) { bool row_repeat = false; @@ -1789,12 +1651,11 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, enum omap_color_mode color_mode) { u32 fclk = 0; - /* FIXME venc pclk? */ - u64 tmp, pclk = dispc_pclk_rate(channel); + u64 tmp, pclk = dispc_mgr_pclk_rate(channel); if (height > out_height) { - /* FIXME get real display PPL */ - unsigned int ppl = 800; + struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); + unsigned int ppl = dssdev->panel.timings.x_res; tmp = pclk * height * out_width; do_div(tmp, 2 * out_height * ppl); @@ -1846,114 +1707,120 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, else vf = 1; - /* FIXME venc pclk? */ - return dispc_pclk_rate(channel) * vf * hf; + return dispc_mgr_pclk_rate(channel) * vf * hf; } -int dispc_setup_plane(enum omap_plane plane, - u32 paddr, u16 screen_width, - u16 pos_x, u16 pos_y, - u16 width, u16 height, +static int dispc_ovl_calc_scaling(enum omap_plane plane, + enum omap_channel channel, u16 width, u16 height, u16 out_width, u16 out_height, - enum omap_color_mode color_mode, - bool ilace, - enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, - u8 global_alpha, u8 pre_mult_alpha, - enum omap_channel channel, u32 puv_addr) -{ - const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; - bool five_taps = 0; - bool fieldmode = 0; - int cconv = 0; - unsigned offset0, offset1; - s32 row_inc; - s32 pix_inc; - u16 frame_height = height; - unsigned int field_offset = 0; + enum omap_color_mode color_mode, bool *five_taps) +{ + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + unsigned long fclk = 0; - DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " - "%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, channel); + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { + if (width != out_width || height != out_height) + return -EINVAL; + else + return 0; + } - if (paddr == 0) + if (out_width < width / maxdownscale || + out_width > width * 8) return -EINVAL; - if (ilace && height == out_height) - fieldmode = 1; + if (out_height < height / maxdownscale || + out_height > height * 8) + return -EINVAL; - if (ilace) { - if (fieldmode) - height /= 2; - pos_y /= 2; - out_height /= 2; + /* Must use 5-tap filter? */ + *five_taps = height > out_height * 2; - DSSDBG("adjusting for ilace: height %d, pos_y %d, " - "out_height %d\n", - height, pos_y, out_height); + if (!*five_taps) { + 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 && + fclk > dispc_fclk_rate()) + *five_taps = true; } - if (!dss_feat_color_mode_supported(plane, color_mode)) + if (width > (2048 >> *five_taps)) { + DSSERR("failed to set up scaling, fclk too low\n"); return -EINVAL; + } - if (plane == OMAP_DSS_GFX) { - if (width != out_width || height != out_height) - return -EINVAL; - } else { - /* video plane */ + if (*five_taps) + fclk = calc_fclk_five_taps(channel, width, height, + out_width, out_height, color_mode); - unsigned long fclk = 0; + DSSDBG("required fclk rate = %lu Hz\n", fclk); + DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); - if (out_width < width / maxdownscale || - out_width > width * 8) - return -EINVAL; + if (!fclk || fclk > dispc_fclk_rate()) { + DSSERR("failed to set up scaling, " + "required fclk rate = %lu Hz, " + "current fclk rate = %lu Hz\n", + fclk, dispc_fclk_rate()); + return -EINVAL; + } - if (out_height < height / maxdownscale || - out_height > height * 8) - return -EINVAL; + return 0; +} - if (color_mode == OMAP_DSS_COLOR_YUV2 || - color_mode == OMAP_DSS_COLOR_UYVY || - color_mode == OMAP_DSS_COLOR_NV12) - cconv = 1; +int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, + bool ilace, enum omap_channel channel, bool replication, + u32 fifo_low, u32 fifo_high) +{ + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + bool five_taps = false; + bool fieldmode = 0; + int r, cconv = 0; + unsigned offset0, offset1; + s32 row_inc; + s32 pix_inc; + u16 frame_height = oi->height; + unsigned int field_offset = 0; - /* Must use 5-tap filter? */ - five_taps = height > out_height * 2; + DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " + "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d " + "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr, + oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, + oi->out_width, oi->out_height, oi->color_mode, oi->rotation, + oi->mirror, ilace, channel, replication, fifo_low, fifo_high); - if (!five_taps) { - fclk = calc_fclk(channel, width, height, out_width, - out_height); + if (oi->paddr == 0) + return -EINVAL; - /* Try 5-tap filter if 3-tap fclk is too high */ - if (cpu_is_omap34xx() && height > out_height && - fclk > dispc_fclk_rate()) - five_taps = true; - } + if (ilace && oi->height == oi->out_height) + fieldmode = 1; - if (width > (2048 >> five_taps)) { - DSSERR("failed to set up scaling, fclk too low\n"); - return -EINVAL; - } + if (ilace) { + if (fieldmode) + oi->height /= 2; + oi->pos_y /= 2; + oi->out_height /= 2; - if (five_taps) - fclk = calc_fclk_five_taps(channel, width, height, - out_width, out_height, color_mode); + DSSDBG("adjusting for ilace: height %d, pos_y %d, " + "out_height %d\n", + oi->height, oi->pos_y, oi->out_height); + } - DSSDBG("required fclk rate = %lu Hz\n", fclk); - DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); + if (!dss_feat_color_mode_supported(plane, oi->color_mode)) + return -EINVAL; - if (!fclk || fclk > dispc_fclk_rate()) { - DSSERR("failed to set up scaling, " - "required fclk rate = %lu Hz, " - "current fclk rate = %lu Hz\n", - fclk, dispc_fclk_rate()); - return -EINVAL; - } - } + r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, + oi->out_width, oi->out_height, oi->color_mode, + &five_taps); + if (r) + return r; + + if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || + oi->color_mode == OMAP_DSS_COLOR_UYVY || + oi->color_mode == OMAP_DSS_COLOR_NV12) + cconv = 1; if (ilace && !fieldmode) { /* @@ -1963,69 +1830,76 @@ int dispc_setup_plane(enum omap_plane plane, * so the integer part must be added to the base address of the * bottom field. */ - if (!height || height == out_height) + if (!oi->height || oi->height == oi->out_height) field_offset = 0; else - field_offset = height / out_height / 2; + field_offset = oi->height / oi->out_height / 2; } /* Fields are independent but interleaved in memory. */ if (fieldmode) field_offset = 1; - if (rotation_type == OMAP_DSS_ROT_DMA) - calc_dma_rotation_offset(rotation, mirror, - screen_width, width, frame_height, color_mode, - fieldmode, field_offset, + if (oi->rotation_type == OMAP_DSS_ROT_DMA) + calc_dma_rotation_offset(oi->rotation, oi->mirror, + oi->screen_width, oi->width, frame_height, + oi->color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc); else - calc_vrfb_rotation_offset(rotation, mirror, - screen_width, width, frame_height, color_mode, - fieldmode, field_offset, + calc_vrfb_rotation_offset(oi->rotation, oi->mirror, + oi->screen_width, oi->width, frame_height, + oi->color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc); DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); - _dispc_set_color_mode(plane, color_mode); + dispc_ovl_set_color_mode(plane, oi->color_mode); - _dispc_set_plane_ba0(plane, paddr + offset0); - _dispc_set_plane_ba1(plane, paddr + offset1); + dispc_ovl_set_ba0(plane, oi->paddr + offset0); + dispc_ovl_set_ba1(plane, oi->paddr + offset1); - if (OMAP_DSS_COLOR_NV12 == color_mode) { - _dispc_set_plane_ba0_uv(plane, puv_addr + offset0); - _dispc_set_plane_ba1_uv(plane, puv_addr + offset1); + if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { + dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); + dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); } - _dispc_set_row_inc(plane, row_inc); - _dispc_set_pix_inc(plane, pix_inc); + dispc_ovl_set_row_inc(plane, row_inc); + dispc_ovl_set_pix_inc(plane, pix_inc); - DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height, - out_width, out_height); + DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, + oi->height, oi->out_width, oi->out_height); - _dispc_set_plane_pos(plane, pos_x, pos_y); + dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); - _dispc_set_pic_size(plane, width, height); + dispc_ovl_set_pic_size(plane, oi->width, oi->height); - if (plane != OMAP_DSS_GFX) { - _dispc_set_scaling(plane, width, height, - out_width, out_height, + if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { + dispc_ovl_set_scaling(plane, oi->width, oi->height, + oi->out_width, oi->out_height, ilace, five_taps, fieldmode, - color_mode, rotation); - _dispc_set_vid_size(plane, out_width, out_height); - _dispc_set_vid_color_conv(plane, cconv); + oi->color_mode, oi->rotation); + dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height); + dispc_ovl_set_vid_color_conv(plane, cconv); } - _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode); + dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, + oi->color_mode); + + dispc_ovl_set_zorder(plane, oi->zorder); + dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); + dispc_ovl_setup_global_alpha(plane, oi->global_alpha); - _dispc_set_pre_mult_alpha(plane, pre_mult_alpha); - _dispc_setup_global_alpha(plane, global_alpha); + dispc_ovl_set_channel_out(plane, channel); + + dispc_ovl_enable_replication(plane, replication); + dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); return 0; } -int dispc_enable_plane(enum omap_plane plane, bool enable) +int dispc_ovl_enable(enum omap_plane plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); @@ -2048,7 +1922,7 @@ static void _enable_lcd_out(enum omap_channel channel, bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } -static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) { struct completion frame_done_completion; bool is_on; @@ -2095,14 +1969,19 @@ static void _enable_digit_out(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); } -static void dispc_enable_digit_out(bool enable) +static void dispc_mgr_enable_digit_out(bool enable) { struct completion frame_done_completion; - int r; + enum dss_hdmi_venc_clk_source_select src; + int r, i; + u32 irq_mask; + int num_irqs; if (REG_GET(DISPC_CONTROL, 1, 1) == enable) return; + src = dss_get_hdmi_venc_clk_source(); + if (enable) { unsigned long flags; /* When we enable digit output, we'll get an extra digit @@ -2119,43 +1998,47 @@ static void dispc_enable_digit_out(bool enable) * wait for the extra sync losts */ init_completion(&frame_done_completion); + if (src == DSS_HDMI_M_PCLK && enable == false) { + irq_mask = DISPC_IRQ_FRAMEDONETV; + num_irqs = 1; + } else { + irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; + /* XXX I understand from TRM that we should only wait for the + * current field to complete. But it seems we have to wait for + * both fields */ + num_irqs = 2; + } + r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, - DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD); + irq_mask); if (r) - DSSERR("failed to register EVSYNC isr\n"); + DSSERR("failed to register %x isr\n", irq_mask); _enable_digit_out(enable); - /* XXX I understand from TRM that we should only wait for the - * current field to complete. But it seems we have to wait - * for both fields */ - if (!wait_for_completion_timeout(&frame_done_completion, - msecs_to_jiffies(100))) - DSSERR("timeout waiting for EVSYNC\n"); - - if (!wait_for_completion_timeout(&frame_done_completion, - msecs_to_jiffies(100))) - DSSERR("timeout waiting for EVSYNC\n"); + for (i = 0; i < num_irqs; ++i) { + if (!wait_for_completion_timeout(&frame_done_completion, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for digit out to %s\n", + enable ? "start" : "stop"); + } - r = omap_dispc_unregister_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD); + r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion, + irq_mask); if (r) - DSSERR("failed to unregister EVSYNC isr\n"); + DSSERR("failed to unregister %x isr\n", irq_mask); if (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.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT; dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); } } -bool dispc_is_channel_enabled(enum omap_channel channel) +bool dispc_mgr_is_enabled(enum omap_channel channel) { if (channel == OMAP_DSS_CHANNEL_LCD) return !!REG_GET(DISPC_CONTROL, 0, 0); @@ -2167,13 +2050,12 @@ bool dispc_is_channel_enabled(enum omap_channel channel) BUG(); } -void dispc_enable_channel(enum omap_channel channel, bool enable) +void dispc_mgr_enable(enum omap_channel channel, bool enable) { - if (channel == OMAP_DSS_CHANNEL_LCD || - channel == OMAP_DSS_CHANNEL_LCD2) - dispc_enable_lcd_out(channel, enable); + if (dispc_mgr_is_lcd(channel)) + dispc_mgr_enable_lcd_out(channel, enable); else if (channel == OMAP_DSS_CHANNEL_DIGIT) - dispc_enable_digit_out(enable); + dispc_mgr_enable_digit_out(enable); else BUG(); } @@ -2202,7 +2084,7 @@ void dispc_pck_free_enable(bool enable) REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); } -void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) +void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) { if (channel == OMAP_DSS_CHANNEL_LCD2) REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); @@ -2211,7 +2093,7 @@ void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) } -void dispc_set_lcd_display_type(enum omap_channel channel, +void dispc_mgr_set_lcd_display_type(enum omap_channel channel, enum omap_lcd_display_type type) { int mode; @@ -2242,12 +2124,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) } -void dispc_set_default_color(enum omap_channel channel, u32 color) +void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) { dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); } -u32 dispc_get_default_color(enum omap_channel channel) +u32 dispc_mgr_get_default_color(enum omap_channel channel) { u32 l; @@ -2260,7 +2142,7 @@ u32 dispc_get_default_color(enum omap_channel channel) return l; } -void dispc_set_trans_key(enum omap_channel ch, +void dispc_mgr_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { @@ -2274,7 +2156,7 @@ void dispc_set_trans_key(enum omap_channel ch, dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); } -void dispc_get_trans_key(enum omap_channel ch, +void dispc_mgr_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { @@ -2293,7 +2175,7 @@ void dispc_get_trans_key(enum omap_channel ch, *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); } -void dispc_enable_trans_key(enum omap_channel ch, bool enable) +void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) { if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); @@ -2302,39 +2184,36 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable) else /* OMAP_DSS_CHANNEL_LCD2 */ REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); } -void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) + +void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) { - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) + if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) return; if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); 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); } -bool dispc_alpha_blending_enabled(enum omap_channel ch) + +bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch) { bool enabled; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) + if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) return false; 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, 19, 19); - else if (ch == OMAP_DSS_CHANNEL_LCD2) - enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); return enabled; } - -bool dispc_trans_key_enabled(enum omap_channel ch) +bool dispc_mgr_trans_key_enabled(enum omap_channel ch) { bool enabled; @@ -2351,7 +2230,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) } -void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) +void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -2379,46 +2258,41 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); } -void dispc_set_parallel_interface_mode(enum omap_channel channel, - enum omap_parallel_interface_mode mode) +void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) { u32 l; - int stallmode; - int gpout0 = 1; - int gpout1; + int gpout0, gpout1; switch (mode) { - case OMAP_DSS_PARALLELMODE_BYPASS: - stallmode = 0; - gpout1 = 1; + case DSS_IO_PAD_MODE_RESET: + gpout0 = 0; + gpout1 = 0; break; - - case OMAP_DSS_PARALLELMODE_RFBI: - stallmode = 1; + case DSS_IO_PAD_MODE_RFBI: + gpout0 = 1; gpout1 = 0; break; - - case OMAP_DSS_PARALLELMODE_DSI: - stallmode = 1; + case DSS_IO_PAD_MODE_BYPASS: + gpout0 = 1; gpout1 = 1; break; - default: BUG(); return; } - 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); - } + l = dispc_read_reg(DISPC_CONTROL); + l = FLD_MOD(l, gpout0, 15, 15); + l = FLD_MOD(l, gpout1, 16, 16); + dispc_write_reg(DISPC_CONTROL, l); +} + +void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) +{ + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, enable, 11, 11); + else + REG_FLD_MOD(DISPC_CONTROL, enable, 11, 11); } static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, @@ -2452,7 +2326,7 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings) timings->vfp, timings->vbp); } -static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, +static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, int hfp, int hbp, int vsw, int vfp, int vbp) { u32 timing_h, timing_v; @@ -2476,7 +2350,7 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, } /* change name to mode? */ -void dispc_set_lcd_timings(enum omap_channel channel, +void dispc_mgr_set_lcd_timings(enum omap_channel channel, struct omap_video_timings *timings) { unsigned xtot, ytot; @@ -2487,11 +2361,11 @@ void dispc_set_lcd_timings(enum omap_channel channel, timings->vfp, timings->vbp)) BUG(); - _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp, + _dispc_mgr_set_lcd_timings(channel, timings->hsw, timings->hfp, timings->hbp, timings->vsw, timings->vfp, timings->vbp); - dispc_set_lcd_size(channel, timings->x_res, timings->y_res); + dispc_mgr_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; @@ -2509,17 +2383,17 @@ void dispc_set_lcd_timings(enum omap_channel channel, DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); } -static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, +static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, u16 pck_div) { BUG_ON(lck_div < 1); - BUG_ON(pck_div < 2); + BUG_ON(pck_div < 1); dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); } -static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, +static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, int *pck_div) { u32 l; @@ -2552,7 +2426,7 @@ unsigned long dispc_fclk_rate(void) return r; } -unsigned long dispc_lclk_rate(enum omap_channel channel) +unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) { struct platform_device *dsidev; int lcd; @@ -2582,19 +2456,34 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) return r / lcd; } -unsigned long dispc_pclk_rate(enum omap_channel channel) +unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) { - int pcd; unsigned long r; - u32 l; - l = dispc_read_reg(DISPC_DIVISORo(channel)); + if (dispc_mgr_is_lcd(channel)) { + int pcd; + u32 l; - pcd = FLD_GET(l, 7, 0); + l = dispc_read_reg(DISPC_DIVISORo(channel)); - r = dispc_lclk_rate(channel); + pcd = FLD_GET(l, 7, 0); - return r / pcd; + r = dispc_mgr_lclk_rate(channel); + + return r / pcd; + } else { + struct omap_dss_device *dssdev = + dispc_mgr_get_device(channel); + + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_VENC: + return venc_get_pixel_clock(); + case OMAP_DISPLAY_TYPE_HDMI: + return hdmi_get_pixel_clock(); + default: + BUG(); + } + } } void dispc_dump_clocks(struct seq_file *s) @@ -2631,12 +2520,12 @@ void dispc_dump_clocks(struct seq_file *s) dss_get_generic_clk_source_name(lcd_clk_src), dss_feat_get_clk_source_name(lcd_clk_src)); - dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); + dispc_mgr_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); + dispc_mgr_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); + dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); if (dss_has_feature(FEAT_MGR_LCD2)) { seq_printf(s, "- LCD2 -\n"); @@ -2646,12 +2535,12 @@ void dispc_dump_clocks(struct seq_file *s) dss_get_generic_clk_source_name(lcd_clk_src), dss_feat_get_clk_source_name(lcd_clk_src)); - dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); + dispc_mgr_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); + dispc_mgr_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); + dispc_mgr_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); } dispc_runtime_put(); @@ -2692,6 +2581,10 @@ void dispc_dump_irqs(struct seq_file *s) PIS(VID1_END_WIN); PIS(VID2_FIFO_UNDERFLOW); PIS(VID2_END_WIN); + if (dss_feat_get_num_ovls() > 3) { + PIS(VID3_FIFO_UNDERFLOW); + PIS(VID3_END_WIN); + } PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); PIS(WAKEUP); @@ -2707,11 +2600,26 @@ void dispc_dump_irqs(struct seq_file *s) void dispc_dump_regs(struct seq_file *s) { + int i, j; + const char *mgr_names[] = { + [OMAP_DSS_CHANNEL_LCD] = "LCD", + [OMAP_DSS_CHANNEL_DIGIT] = "TV", + [OMAP_DSS_CHANNEL_LCD2] = "LCD2", + }; + const char *ovl_names[] = { + [OMAP_DSS_GFX] = "GFX", + [OMAP_DSS_VIDEO1] = "VID1", + [OMAP_DSS_VIDEO2] = "VID2", + [OMAP_DSS_VIDEO3] = "VID3", + }; + const char **p_names; + #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) if (dispc_runtime_get()) return; + /* DISPC common registers */ DUMPREG(DISPC_REVISION); DUMPREG(DISPC_SYSCONFIG); DUMPREG(DISPC_SYSSTATUS); @@ -2720,247 +2628,139 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_CONTROL); DUMPREG(DISPC_CONFIG); DUMPREG(DISPC_CAPABLE); - DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT)); - DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT)); DUMPREG(DISPC_LINE_STATUS); DUMPREG(DISPC_LINE_NUMBER); - DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD)); - if (dss_has_feature(FEAT_GLOBAL_ALPHA)) + if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || + dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) DUMPREG(DISPC_GLOBAL_ALPHA); - DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); - DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); if (dss_has_feature(FEAT_MGR_LCD2)) { DUMPREG(DISPC_CONTROL2); DUMPREG(DISPC_CONFIG2); - DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD2)); - } - - DUMPREG(DISPC_OVL_BA0(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_BA1(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_WINDOW_SKIP(OMAP_DSS_GFX)); - DUMPREG(DISPC_OVL_TABLE_BA(OMAP_DSS_GFX)); - - DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); - - if (dss_has_feature(FEAT_CPR)) { - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); } - if (dss_has_feature(FEAT_MGR_LCD2)) { - DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); + +#undef DUMPREG + +#define DISPC_REG(i, name) name(i) +#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ + 48 - strlen(#r) - strlen(p_names[i]), " ", \ + dispc_read_reg(DISPC_REG(i, r))) + + p_names = mgr_names; + + /* DISPC channel specific registers */ + for (i = 0; i < dss_feat_get_num_mgrs(); i++) { + DUMPREG(i, DISPC_DEFAULT_COLOR); + DUMPREG(i, DISPC_TRANS_COLOR); + DUMPREG(i, DISPC_SIZE_MGR); + + if (i == OMAP_DSS_CHANNEL_DIGIT) + continue; + + DUMPREG(i, DISPC_DEFAULT_COLOR); + DUMPREG(i, DISPC_TRANS_COLOR); + DUMPREG(i, DISPC_TIMING_H); + DUMPREG(i, DISPC_TIMING_V); + DUMPREG(i, DISPC_POL_FREQ); + DUMPREG(i, DISPC_DIVISORo); + DUMPREG(i, DISPC_SIZE_MGR); + + DUMPREG(i, DISPC_DATA_CYCLE1); + DUMPREG(i, DISPC_DATA_CYCLE2); + DUMPREG(i, DISPC_DATA_CYCLE3); if (dss_has_feature(FEAT_CPR)) { - DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); - DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); + DUMPREG(i, DISPC_CPR_COEF_R); + DUMPREG(i, DISPC_CPR_COEF_G); + DUMPREG(i, DISPC_CPR_COEF_B); + } + } + + p_names = ovl_names; + + for (i = 0; i < dss_feat_get_num_ovls(); i++) { + DUMPREG(i, DISPC_OVL_BA0); + DUMPREG(i, DISPC_OVL_BA1); + DUMPREG(i, DISPC_OVL_POSITION); + DUMPREG(i, DISPC_OVL_SIZE); + DUMPREG(i, DISPC_OVL_ATTRIBUTES); + DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); + DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); + DUMPREG(i, DISPC_OVL_ROW_INC); + DUMPREG(i, DISPC_OVL_PIXEL_INC); + if (dss_has_feature(FEAT_PRELOAD)) + DUMPREG(i, DISPC_OVL_PRELOAD); + + if (i == OMAP_DSS_GFX) { + DUMPREG(i, DISPC_OVL_WINDOW_SKIP); + DUMPREG(i, DISPC_OVL_TABLE_BA); + continue; + } + + DUMPREG(i, DISPC_OVL_FIR); + DUMPREG(i, DISPC_OVL_PICTURE_SIZE); + DUMPREG(i, DISPC_OVL_ACCU0); + DUMPREG(i, DISPC_OVL_ACCU1); + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + DUMPREG(i, DISPC_OVL_BA0_UV); + DUMPREG(i, DISPC_OVL_BA1_UV); + DUMPREG(i, DISPC_OVL_FIR2); + DUMPREG(i, DISPC_OVL_ACCU2_0); + DUMPREG(i, DISPC_OVL_ACCU2_1); } + if (dss_has_feature(FEAT_ATTR2)) + DUMPREG(i, DISPC_OVL_ATTRIBUTES2); + if (dss_has_feature(FEAT_PRELOAD)) + DUMPREG(i, DISPC_OVL_PRELOAD); } - if (dss_has_feature(FEAT_PRELOAD)) - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); - - DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1)); - - DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2)); - - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4)); - if (dss_has_feature(FEAT_FIR_COEF_V)) { - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); - } - - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1)); - - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7)); - } - if (dss_has_feature(FEAT_ATTR2)) - DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); - - - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4)); - - if (dss_has_feature(FEAT_FIR_COEF_V)) { - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); - } - - if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { - DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2)); - DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2)); - - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7)); - - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6)); - DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7)); - } - if (dss_has_feature(FEAT_ATTR2)) - DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); - - if (dss_has_feature(FEAT_PRELOAD)) { - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); - DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); +#undef DISPC_REG +#undef DUMPREG + +#define DISPC_REG(plane, name, i) name(plane, i) +#define DUMPREG(plane, name, i) \ + seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ + 46 - strlen(#name) - strlen(p_names[plane]), " ", \ + dispc_read_reg(DISPC_REG(plane, name, i))) + + /* Video pipeline coefficient registers */ + + /* start from OMAP_DSS_VIDEO1 */ + for (i = 1; i < dss_feat_get_num_ovls(); i++) { + for (j = 0; j < 8; j++) + DUMPREG(i, DISPC_OVL_FIR_COEF_H, j); + + for (j = 0; j < 8; j++) + DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j); + + for (j = 0; j < 5; j++) + DUMPREG(i, DISPC_OVL_CONV_COEF, j); + + if (dss_has_feature(FEAT_FIR_COEF_V)) { + for (j = 0; j < 8; j++) + DUMPREG(i, DISPC_OVL_FIR_COEF_V, j); + } + + if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { + for (j = 0; j < 8; j++) + DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j); + + for (j = 0; j < 8; j++) + DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j); + + for (j = 0; j < 8; j++) + DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j); + } } dispc_runtime_put(); + +#undef DISPC_REG #undef DUMPREG } -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) +static void _dispc_mgr_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; @@ -2979,10 +2779,10 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, dispc_write_reg(DISPC_POL_FREQ(channel), l); } -void dispc_set_pol_freq(enum omap_channel channel, +void dispc_mgr_set_pol_freq(enum omap_channel channel, enum omap_panel_config config, u8 acbi, u8 acb) { - _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, + _dispc_mgr_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, @@ -2995,11 +2795,17 @@ void dispc_set_pol_freq(enum omap_channel channel, void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, struct dispc_clock_info *cinfo) { - u16 pcd_min = is_tft ? 2 : 3; + u16 pcd_min, pcd_max; unsigned long best_pck; u16 best_ld, cur_ld; u16 best_pd, cur_pd; + pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); + pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); + + if (!is_tft) + pcd_min = 3; + best_pck = 0; best_ld = 0; best_pd = 0; @@ -3007,7 +2813,7 @@ void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { unsigned long lck = fck / cur_ld; - for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) { + for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) { unsigned long pck = lck / cur_pd; long old_delta = abs(best_pck - req_pck); long new_delta = abs(pck - req_pck); @@ -3042,7 +2848,7 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, { if (cinfo->lck_div > 255 || cinfo->lck_div == 0) return -EINVAL; - if (cinfo->pck_div < 2 || cinfo->pck_div > 255) + if (cinfo->pck_div < 1 || cinfo->pck_div > 255) return -EINVAL; cinfo->lck = dispc_fclk_rate / cinfo->lck_div; @@ -3051,18 +2857,18 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } -int dispc_set_clock_div(enum omap_channel channel, +int dispc_mgr_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(channel, cinfo->lck_div, cinfo->pck_div); + dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); return 0; } -int dispc_get_clock_div(enum omap_channel channel, +int dispc_mgr_get_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo) { unsigned long fck; @@ -3207,6 +3013,8 @@ static void print_irq_status(u32 status) PIS(OCP_ERR); PIS(VID1_FIFO_UNDERFLOW); PIS(VID2_FIFO_UNDERFLOW); + if (dss_feat_get_num_ovls() > 3) + PIS(VID3_FIFO_UNDERFLOW); PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); if (dss_has_feature(FEAT_MGR_LCD2)) @@ -3300,178 +3108,72 @@ static void dispc_error_worker(struct work_struct *work) int i; u32 errors; unsigned long flags; + static const unsigned fifo_underflow_bits[] = { + DISPC_IRQ_GFX_FIFO_UNDERFLOW, + DISPC_IRQ_VID1_FIFO_UNDERFLOW, + DISPC_IRQ_VID2_FIFO_UNDERFLOW, + DISPC_IRQ_VID3_FIFO_UNDERFLOW, + }; + + static const unsigned sync_lost_bits[] = { + DISPC_IRQ_SYNC_LOST, + DISPC_IRQ_SYNC_LOST_DIGIT, + DISPC_IRQ_SYNC_LOST2, + }; spin_lock_irqsave(&dispc.irq_lock, flags); errors = dispc.error_irqs; dispc.error_irqs = 0; spin_unlock_irqrestore(&dispc.irq_lock, flags); - if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) { - DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n"); - 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) { - dispc_enable_plane(ovl->id, 0); - dispc_go(ovl->manager->id); - mdelay(50); - break; - } - } - } - - if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) { - DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n"); - 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 == 1) { - dispc_enable_plane(ovl->id, 0); - dispc_go(ovl->manager->id); - mdelay(50); - break; - } - } - } - - if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) { - DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n"); - 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; + dispc_runtime_get(); - if (ovl->id == 2) { - dispc_enable_plane(ovl->id, 0); - dispc_go(ovl->manager->id); - mdelay(50); - break; - } - } - } - - if (errors & DISPC_IRQ_SYNC_LOST) { - struct omap_overlay_manager *manager = NULL; - bool enable = false; + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl; + unsigned bit; - DSSERR("SYNC_LOST, disabling LCD\n"); + ovl = omap_dss_get_overlay(i); + bit = fifo_underflow_bits[i]; - 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_LCD) { - 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); + if (bit & errors) { + DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", + ovl->name); + dispc_ovl_enable(ovl->id, false); + dispc_mgr_go(ovl->manager->id); mdelay(50); - if (enable) - dssdev->driver->enable(dssdev); } } - if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) { - struct omap_overlay_manager *manager = NULL; - bool enable = false; + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + struct omap_overlay_manager *mgr; + unsigned bit; - DSSERR("SYNC_LOST_DIGIT, disabling TV\n"); + mgr = omap_dss_get_overlay_manager(i); + bit = sync_lost_bits[i]; - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - struct omap_overlay_manager *mgr; - mgr = omap_dss_get_overlay_manager(i); + if (bit & errors) { + struct omap_dss_device *dssdev = mgr->device; + bool enable; - if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) { - manager = mgr; - enable = mgr->device->state == - OMAP_DSS_DISPLAY_ACTIVE; - mgr->device->driver->disable(mgr->device); - break; - } - } + DSSERR("SYNC_LOST on channel %s, restarting the output " + "with video overlays disabled\n", + mgr->name); - 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); - } + enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; + dssdev->driver->disable(dssdev); - dispc_go(manager->id); - mdelay(50); - if (enable) - dssdev->driver->enable(dssdev); - } - } - - 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); + if (ovl->id != OMAP_DSS_GFX && + ovl->manager == mgr) + dispc_ovl_enable(ovl->id, false); } - dispc_go(manager->id); + dispc_mgr_go(mgr->id); mdelay(50); + if (enable) dssdev->driver->enable(dssdev); } @@ -3482,9 +3184,7 @@ static void dispc_error_worker(struct work_struct *work) 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->caps & OMAP_DSS_OVL_CAP_DISPC) - mgr->device->driver->disable(mgr->device); + mgr->device->driver->disable(mgr->device); } } @@ -3492,6 +3192,8 @@ static void dispc_error_worker(struct work_struct *work) dispc.irq_error_mask |= errors; _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); + + dispc_runtime_put(); } int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) @@ -3586,6 +3288,8 @@ static void _omap_dispc_initialize_irq(void) dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; if (dss_has_feature(FEAT_MGR_LCD2)) dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; + if (dss_feat_get_num_ovls() > 3) + dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, * so clear it */ @@ -3635,6 +3339,8 @@ static void _omap_dispc_initial_config(void) dispc_read_plane_fifo_sizes(); dispc_configure_burst_sizes(); + + dispc_ovl_enable_zorder_planes(); } /* DISPC HW IP initialisation */ @@ -3734,7 +3440,6 @@ static int omap_dispchw_remove(struct platform_device *pdev) static int dispc_runtime_suspend(struct device *dev) { dispc_save_context(); - clk_disable(dispc.dss_clk); dss_runtime_put(); return 0; @@ -3748,7 +3453,6 @@ static int dispc_runtime_resume(struct device *dev) if (r < 0) return r; - clk_enable(dispc.dss_clk); dispc_restore_context(); return 0; diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 6c9ee0a..c06efc3 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -291,6 +291,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) return 0x00BC; case OMAP_DSS_VIDEO2: return 0x014C; + case OMAP_DSS_VIDEO3: + return 0x0300; default: BUG(); } @@ -304,6 +306,8 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0000; + case OMAP_DSS_VIDEO3: + return 0x0008; default: BUG(); } @@ -316,6 +320,8 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0004; + case OMAP_DSS_VIDEO3: + return 0x000C; default: BUG(); } @@ -330,6 +336,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) return 0x0544; case OMAP_DSS_VIDEO2: return 0x04BC; + case OMAP_DSS_VIDEO3: + return 0x0310; default: BUG(); } @@ -344,6 +352,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) return 0x0548; case OMAP_DSS_VIDEO2: return 0x04C0; + case OMAP_DSS_VIDEO3: + return 0x0314; default: BUG(); } @@ -356,6 +366,8 @@ static inline u16 DISPC_POS_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0008; + case OMAP_DSS_VIDEO3: + return 0x009C; default: BUG(); } @@ -368,6 +380,8 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x000C; + case OMAP_DSS_VIDEO3: + return 0x00A8; default: BUG(); } @@ -381,6 +395,8 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0010; + case OMAP_DSS_VIDEO3: + return 0x0070; default: BUG(); } @@ -395,6 +411,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) return 0x0568; case OMAP_DSS_VIDEO2: return 0x04DC; + case OMAP_DSS_VIDEO3: + return 0x032C; default: BUG(); } @@ -408,6 +426,8 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0014; + case OMAP_DSS_VIDEO3: + return 0x008C; default: BUG(); } @@ -421,6 +441,8 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0018; + case OMAP_DSS_VIDEO3: + return 0x0088; default: BUG(); } @@ -434,6 +456,8 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x001C; + case OMAP_DSS_VIDEO3: + return 0x00A4; default: BUG(); } @@ -447,6 +471,8 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0020; + case OMAP_DSS_VIDEO3: + return 0x0098; default: BUG(); } @@ -459,6 +485,7 @@ static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane) return 0x0034; case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: BUG(); default: BUG(); @@ -472,6 +499,7 @@ static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane) return 0x0038; case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: BUG(); default: BUG(); @@ -486,6 +514,8 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0024; + case OMAP_DSS_VIDEO3: + return 0x0090; default: BUG(); } @@ -500,6 +530,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) return 0x0580; case OMAP_DSS_VIDEO2: return 0x055C; + case OMAP_DSS_VIDEO3: + return 0x0424; default: BUG(); } @@ -513,6 +545,8 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0028; + case OMAP_DSS_VIDEO3: + return 0x0094; default: BUG(); } @@ -527,6 +561,8 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x002C; + case OMAP_DSS_VIDEO3: + return 0x0000; default: BUG(); } @@ -541,6 +577,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) return 0x0584; case OMAP_DSS_VIDEO2: return 0x0560; + case OMAP_DSS_VIDEO3: + return 0x0428; default: BUG(); } @@ -554,6 +592,8 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0030; + case OMAP_DSS_VIDEO3: + return 0x0004; default: BUG(); } @@ -568,6 +608,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) return 0x0588; case OMAP_DSS_VIDEO2: return 0x0564; + case OMAP_DSS_VIDEO3: + return 0x042C; default: BUG(); } @@ -582,6 +624,8 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0034 + i * 0x8; + case OMAP_DSS_VIDEO3: + return 0x0010 + i * 0x8; default: BUG(); } @@ -597,6 +641,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) return 0x058C + i * 0x8; case OMAP_DSS_VIDEO2: return 0x0568 + i * 0x8; + case OMAP_DSS_VIDEO3: + return 0x0430 + i * 0x8; default: BUG(); } @@ -611,6 +657,8 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: return 0x0038 + i * 0x8; + case OMAP_DSS_VIDEO3: + return 0x0014 + i * 0x8; default: BUG(); } @@ -626,6 +674,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) return 0x0590 + i * 8; case OMAP_DSS_VIDEO2: return 0x056C + i * 0x8; + case OMAP_DSS_VIDEO3: + return 0x0434 + i * 0x8; default: BUG(); } @@ -639,6 +689,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) BUG(); case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: return 0x0074 + i * 0x4; default: BUG(); @@ -655,6 +706,8 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) return 0x0124 + i * 0x4; case OMAP_DSS_VIDEO2: return 0x00B4 + i * 0x4; + case OMAP_DSS_VIDEO3: + return 0x0050 + i * 0x4; default: BUG(); } @@ -670,6 +723,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) return 0x05CC + i * 0x4; case OMAP_DSS_VIDEO2: return 0x05A8 + i * 0x4; + case OMAP_DSS_VIDEO3: + return 0x0470 + i * 0x4; default: BUG(); } @@ -684,6 +739,8 @@ static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane) return 0x0174; case OMAP_DSS_VIDEO2: return 0x00E8; + case OMAP_DSS_VIDEO3: + return 0x00A0; default: BUG(); } diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 94495e4..be331dc 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -45,14 +45,13 @@ static ssize_t display_enabled_store(struct device *dev, const char *buf, size_t size) { struct omap_dss_device *dssdev = to_dss_device(dev); - int r, enabled; + int r; + bool enabled; - r = kstrtoint(buf, 0, &enabled); + r = strtobool(buf, &enabled); if (r) return r; - enabled = !!enabled; - if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { if (enabled) { r = dssdev->driver->enable(dssdev); @@ -79,17 +78,16 @@ static ssize_t display_tear_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct omap_dss_device *dssdev = to_dss_device(dev); - int te, r; + int r; + bool te; if (!dssdev->driver->enable_te || !dssdev->driver->get_te) return -ENOENT; - r = kstrtoint(buf, 0, &te); + r = strtobool(buf, &te); if (r) return r; - te = !!te; - r = dssdev->driver->enable_te(dssdev, te); if (r) return r; @@ -195,17 +193,16 @@ static ssize_t display_mirror_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct omap_dss_device *dssdev = to_dss_device(dev); - int mirror, r; + int r; + bool mirror; if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) return -ENOENT; - r = kstrtoint(buf, 0, &mirror); + r = strtobool(buf, &mirror); if (r) return r; - mirror = !!mirror; - r = dssdev->driver->set_mirror(dssdev, mirror); if (r) return r; @@ -302,11 +299,15 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) return 16; case OMAP_DISPLAY_TYPE_DBI: - case OMAP_DISPLAY_TYPE_DSI: if (dssdev->ctrl.pixel_size == 24) return 24; else return 16; + case OMAP_DISPLAY_TYPE_DSI: + if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16) + return 24; + else + return 16; case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: case OMAP_DISPLAY_TYPE_HDMI: @@ -342,9 +343,11 @@ bool dss_use_replication(struct omap_dss_device *dssdev, bpp = 24; break; case OMAP_DISPLAY_TYPE_DBI: - case OMAP_DISPLAY_TYPE_DSI: bpp = dssdev->ctrl.pixel_size; break; + case OMAP_DISPLAY_TYPE_DSI: + bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + break; default: BUG(); } diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index f053b18..483888a 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -82,9 +82,11 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); - r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); - if (r) + r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); + if (r) { + dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); return r; + } *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; *lck_div = dispc_cinfo.lck_div; @@ -109,7 +111,7 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft, if (r) return r; - r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); + r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -129,7 +131,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) bool is_tft; int r = 0; - dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dispc_mgr_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; @@ -153,7 +155,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dispc_set_lcd_timings(dssdev->manager->id, t); + dispc_mgr_set_lcd_timings(dssdev->manager->id, t); return 0; } @@ -164,11 +166,12 @@ static void dpi_basic_init(struct omap_dss_device *dssdev) is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; - dispc_set_parallel_interface_mode(dssdev->manager->id, - OMAP_DSS_PARALLELMODE_BYPASS); - dispc_set_lcd_display_type(dssdev->manager->id, is_tft ? + dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS); + dispc_mgr_enable_stallmode(dssdev->manager->id, false); + + dispc_mgr_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, + dispc_mgr_set_tft_data_lines(dssdev->manager->id, dssdev->phy.dpi.data_lines); } @@ -176,6 +179,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { int r; + if (dssdev->manager == NULL) { + DSSERR("failed to enable display: no manager\n"); + return -ENODEV; + } + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); @@ -277,7 +285,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev, } dpi_set_mode(dssdev); - dispc_go(dssdev->manager->id); + dispc_mgr_go(dssdev->manager->id); dispc_runtime_put(); dss_runtime_put(); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 7adbbeb..43c04a9 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -39,6 +39,7 @@ #include <linux/pm_runtime.h> #include <video/omapdss.h> +#include <video/mipi_display.h> #include <plat/clock.h> #include "dss.h" @@ -131,7 +132,7 @@ struct dsi_reg { u16 idx; }; #define DSI_IRQ_TA_TIMEOUT (1 << 20) #define DSI_IRQ_ERROR_MASK \ (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \ - DSI_IRQ_TA_TIMEOUT) + DSI_IRQ_TA_TIMEOUT | DSI_IRQ_SYNC_LOST) #define DSI_IRQ_CHANNEL_MASK 0xf /* Virtual channel interrupts */ @@ -198,18 +199,6 @@ struct dsi_reg { u16 idx; }; DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \ DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5) -#define DSI_DT_DCS_SHORT_WRITE_0 0x05 -#define DSI_DT_DCS_SHORT_WRITE_1 0x15 -#define DSI_DT_DCS_READ 0x06 -#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37 -#define DSI_DT_NULL_PACKET 0x09 -#define DSI_DT_DCS_LONG_WRITE 0x39 - -#define DSI_DT_RX_ACK_WITH_ERR 0x02 -#define DSI_DT_RX_DCS_LONG_READ 0x1c -#define DSI_DT_RX_SHORT_READ_1 0x21 -#define DSI_DT_RX_SHORT_READ_2 0x22 - typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); #define DSI_MAX_NR_ISRS 2 @@ -228,9 +217,9 @@ enum fifo_size { DSI_FIFO_SIZE_128 = 4, }; -enum dsi_vc_mode { - DSI_VC_MODE_L4 = 0, - DSI_VC_MODE_VP, +enum dsi_vc_source { + DSI_VC_SOURCE_L4 = 0, + DSI_VC_SOURCE_VP, }; enum dsi_lane { @@ -274,7 +263,8 @@ struct dsi_data { struct clk *dss_clk; struct clk *sys_clk; - void (*dsi_mux_pads)(bool enable); + int (*enable_pads)(int dsi_id, unsigned lane_mask); + void (*disable_pads)(int dsi_id, unsigned lane_mask); struct dsi_clock_info current_cinfo; @@ -282,7 +272,7 @@ struct dsi_data { struct regulator *vdds_dsi_reg; struct { - enum dsi_vc_mode mode; + enum dsi_vc_source source; struct omap_dss_device *dssdev; enum fifo_size fifo_size; int vc_id; @@ -368,14 +358,9 @@ struct platform_device *dsi_get_dsidev_from_id(int module) return dsi_pdev_map[module]; } -static int dsi_get_dsidev_id(struct platform_device *dsidev) +static inline int dsi_get_dsidev_id(struct platform_device *dsidev) { - /* TEMP: Pass 0 as the dsi module index till the time the dsi platform - * device names aren't changed to the form "omapdss_dsi.0", - * "omapdss_dsi.1" and so on */ - BUG_ON(dsidev->id != -1); - - return 0; + return dsidev->id; } static inline void dsi_write_reg(struct platform_device *dsidev, @@ -437,6 +422,21 @@ static inline int wait_for_bit_change(struct platform_device *dsidev, return value; } +u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) +{ + switch (fmt) { + case OMAP_DSS_DSI_FMT_RGB888: + case OMAP_DSS_DSI_FMT_RGB666: + return 24; + case OMAP_DSS_DSI_FMT_RGB666_PACKED: + return 18; + case OMAP_DSS_DSI_FMT_RGB565: + return 16; + default: + BUG(); + } +} + #ifdef DEBUG static void dsi_perf_mark_setup(struct platform_device *dsidev) { @@ -453,6 +453,7 @@ static void dsi_perf_mark_start(struct platform_device *dsidev) static void dsi_perf_show(struct platform_device *dsidev, const char *name) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_device *dssdev = dsi->update_region.device; ktime_t t, setup_time, trans_time; u32 total_bytes; u32 setup_us, trans_us, total_us; @@ -476,7 +477,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_bytes = dsi->update_region.w * dsi->update_region.h * - dsi->update_region.device->ctrl.pixel_size / 8; + dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " "%u bytes, %u kbytes/sec\n", @@ -1287,7 +1288,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, * with DSS_SYS_CLK source also */ cinfo->highfreq = 0; } else { - cinfo->clkin = dispc_pclk_rate(dssdev->manager->id); + cinfo->clkin = dispc_mgr_pclk_rate(dssdev->manager->id); if (cinfo->clkin < 32000000) cinfo->highfreq = 0; @@ -2360,6 +2361,24 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) return 0; } +static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) +{ + unsigned lanes = 0; + + if (dssdev->phy.dsi.clk_lane != 0) + lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1); + if (dssdev->phy.dsi.data1_lane != 0) + lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1); + if (dssdev->phy.dsi.data2_lane != 0) + lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1); + if (dssdev->phy.dsi.data3_lane != 0) + lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1); + if (dssdev->phy.dsi.data4_lane != 0) + lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1); + + return lanes; +} + static int dsi_cio_init(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -2370,8 +2389,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) DSSDBGF(); - if (dsi->dsi_mux_pads) - dsi->dsi_mux_pads(true); + r = dsi->enable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); + if (r) + return r; dsi_enable_scp_clk(dsidev); @@ -2452,6 +2472,12 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_cio_timings(dsidev); + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + /* DDR_CLK_ALWAYS_ON */ + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, + dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13); + } + dsi->ulps_enabled = false; DSSDBG("CIO init done\n"); @@ -2467,19 +2493,21 @@ err_cio_pwr: dsi_cio_disable_lane_override(dsidev); err_scp_clk_dom: dsi_disable_scp_clk(dsidev); - if (dsi->dsi_mux_pads) - dsi->dsi_mux_pads(false); + dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); return r; } -static void dsi_cio_uninit(struct platform_device *dsidev) +static void dsi_cio_uninit(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + /* DDR_CLK_ALWAYS_ON */ + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); + dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); dsi_disable_scp_clk(dsidev); - if (dsi->dsi_mux_pads) - dsi->dsi_mux_pads(false); + dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); } static void dsi_config_tx_fifo(struct platform_device *dsidev, @@ -2669,10 +2697,10 @@ static int dsi_sync_vc(struct platform_device *dsidev, int channel) if (!dsi_vc_is_enabled(dsidev, channel)) return 0; - switch (dsi->vc[channel].mode) { - case DSI_VC_MODE_VP: + switch (dsi->vc[channel].source) { + case DSI_VC_SOURCE_VP: return dsi_sync_vc_vp(dsidev, channel); - case DSI_VC_MODE_L4: + case DSI_VC_SOURCE_L4: return dsi_sync_vc_l4(dsidev, channel); default: BUG(); @@ -2726,43 +2754,12 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); } -static int dsi_vc_config_l4(struct platform_device *dsidev, int channel) +static int dsi_vc_config_source(struct platform_device *dsidev, int channel, + enum dsi_vc_source source) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi->vc[channel].mode == DSI_VC_MODE_L4) - return 0; - - DSSDBGF("%d", channel); - - dsi_sync_vc(dsidev, channel); - - dsi_vc_enable(dsidev, channel, 0); - - /* VC_BUSY */ - if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) { - DSSERR("vc(%d) busy when trying to config for L4\n", channel); - return -EIO; - } - - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ - - /* DCS_CMD_ENABLE */ - if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30); - - dsi_vc_enable(dsidev, channel, 1); - - dsi->vc[channel].mode = DSI_VC_MODE_L4; - - return 0; -} - -static int dsi_vc_config_vp(struct platform_device *dsidev, int channel) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - if (dsi->vc[channel].mode == DSI_VC_MODE_VP) + if (dsi->vc[channel].source == source) return 0; DSSDBGF("%d", channel); @@ -2777,21 +2774,22 @@ static int dsi_vc_config_vp(struct platform_device *dsidev, int channel) return -EIO; } - /* SOURCE, 1 = video port */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1); + /* SOURCE, 0 = L4, 1 = video port */ + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1); /* DCS_CMD_ENABLE */ - if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30); + if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { + bool enable = source == DSI_VC_SOURCE_VP; + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30); + } dsi_vc_enable(dsidev, channel, 1); - dsi->vc[channel].mode = DSI_VC_MODE_VP; + dsi->vc[channel].source = source; return 0; } - void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable) { @@ -2810,6 +2808,10 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, dsi_if_enable(dsidev, 1); dsi_force_tx_stop_mode_io(dsidev); + + /* start the DDR clock by sending a NULL packet */ + if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable) + dsi_vc_send_null(dssdev, channel); } EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); @@ -2873,16 +2875,16 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); DSSERR("\trawval %#08x\n", val); dt = FLD_GET(val, 5, 0); - if (dt == DSI_DT_RX_ACK_WITH_ERR) { + if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) { u16 err = FLD_GET(val, 23, 8); dsi_show_rx_ack_with_err(err); - } else if (dt == DSI_DT_RX_SHORT_READ_1) { + } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) { DSSERR("\tDCS short response, 1 byte: %#x\n", FLD_GET(val, 23, 8)); - } else if (dt == DSI_DT_RX_SHORT_READ_2) { + } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) { DSSERR("\tDCS short response, 2 byte: %#x\n", FLD_GET(val, 23, 8)); - } else if (dt == DSI_DT_RX_DCS_LONG_READ) { + } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) { DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); dsi_vc_flush_long_data(dsidev, channel); @@ -3007,7 +3009,7 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, return -EINVAL; } - dsi_vc_config_l4(dsidev, channel); + dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc); @@ -3066,7 +3068,7 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel, channel, data_type, data & 0xff, (data >> 8) & 0xff); - dsi_vc_config_l4(dsidev, channel); + dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) { DSSERR("ERROR FIFO FULL, aborting transfer\n"); @@ -3085,44 +3087,66 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel, int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - u8 nullpkg[] = {0, 0, 0, 0}; - return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg, - 4, 0); + return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL, + 0, 0); } EXPORT_SYMBOL(dsi_vc_send_null); -int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, - u8 *data, int len) +static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, + int channel, u8 *data, int len, enum dss_dsi_content_type type) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - BUG_ON(len == 0); - - if (len == 1) { - r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0, - data[0], 0); + if (len == 0) { + BUG_ON(type == DSS_DSI_CONTENT_DCS); + r = dsi_vc_send_short(dsidev, channel, + MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0); + } else if (len == 1) { + r = dsi_vc_send_short(dsidev, channel, + type == DSS_DSI_CONTENT_GENERIC ? + MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM : + MIPI_DSI_DCS_SHORT_WRITE, data[0], 0); } else if (len == 2) { - r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1, + r = dsi_vc_send_short(dsidev, channel, + type == DSS_DSI_CONTENT_GENERIC ? + MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM : + MIPI_DSI_DCS_SHORT_WRITE_PARAM, data[0] | (data[1] << 8), 0); } else { - /* 0x39 = DCS Long Write */ - r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE, - data, len, 0); + r = dsi_vc_send_long(dsidev, channel, + type == DSS_DSI_CONTENT_GENERIC ? + MIPI_DSI_GENERIC_LONG_WRITE : + MIPI_DSI_DCS_LONG_WRITE, data, len, 0); } return r; } + +int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, + u8 *data, int len) +{ + return dsi_vc_write_nosync_common(dssdev, channel, data, len, + DSS_DSI_CONTENT_DCS); +} EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); -int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data, - int len) +int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, + u8 *data, int len) +{ + return dsi_vc_write_nosync_common(dssdev, channel, data, len, + DSS_DSI_CONTENT_GENERIC); +} +EXPORT_SYMBOL(dsi_vc_generic_write_nosync); + +static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, + u8 *data, int len, enum dss_dsi_content_type type) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len); + r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type); if (r) goto err; @@ -3140,18 +3164,39 @@ int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data, return 0; err: - DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", + DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n", channel, data[0], len); return r; } + +int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data, + int len) +{ + return dsi_vc_write_common(dssdev, channel, data, len, + DSS_DSI_CONTENT_DCS); +} EXPORT_SYMBOL(dsi_vc_dcs_write); +int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data, + int len) +{ + return dsi_vc_write_common(dssdev, channel, data, len, + DSS_DSI_CONTENT_GENERIC); +} +EXPORT_SYMBOL(dsi_vc_generic_write); + int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd) { return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1); } EXPORT_SYMBOL(dsi_vc_dcs_write_0); +int dsi_vc_generic_write_0(struct omap_dss_device *dssdev, int channel) +{ + return dsi_vc_generic_write(dssdev, channel, NULL, 0); +} +EXPORT_SYMBOL(dsi_vc_generic_write_0); + int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, u8 param) { @@ -3162,25 +3207,87 @@ int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, } EXPORT_SYMBOL(dsi_vc_dcs_write_1); -int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, - u8 *buf, int buflen) +int dsi_vc_generic_write_1(struct omap_dss_device *dssdev, int channel, + u8 param) +{ + return dsi_vc_generic_write(dssdev, channel, ¶m, 1); +} +EXPORT_SYMBOL(dsi_vc_generic_write_1); + +int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel, + u8 param1, u8 param2) +{ + u8 buf[2]; + buf[0] = param1; + buf[1] = param2; + return dsi_vc_generic_write(dssdev, channel, buf, 2); +} +EXPORT_SYMBOL(dsi_vc_generic_write_2); + +static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, + int channel, u8 dcs_cmd) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - u32 val; - u8 dt; int r; if (dsi->debug_read) - DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd); + DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n", + channel, dcs_cmd); - r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0); - if (r) - goto err; + r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0); + if (r) { + DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)" + " failed\n", channel, dcs_cmd); + return r; + } - r = dsi_vc_send_bta_sync(dssdev, channel); - if (r) - goto err; + return 0; +} + +static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, + int channel, u8 *reqdata, int reqlen) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + u16 data; + u8 data_type; + int r; + + if (dsi->debug_read) + DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n", + channel, reqlen); + + if (reqlen == 0) { + data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; + data = 0; + } else if (reqlen == 1) { + data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; + data = reqdata[0]; + } else if (reqlen == 2) { + data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; + data = reqdata[0] | (reqdata[1] << 8); + } else { + BUG(); + } + + r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); + if (r) { + DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)" + " failed\n", channel, reqlen); + return r; + } + + return 0; +} + +static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, + u8 *buf, int buflen, enum dss_dsi_content_type type) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + u32 val; + u8 dt; + int r; /* RX_FIFO_NOT_EMPTY */ if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) { @@ -3193,16 +3300,20 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, if (dsi->debug_read) DSSDBG("\theader: %08x\n", val); dt = FLD_GET(val, 5, 0); - if (dt == DSI_DT_RX_ACK_WITH_ERR) { + if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) { u16 err = FLD_GET(val, 23, 8); dsi_show_rx_ack_with_err(err); r = -EIO; goto err; - } else if (dt == DSI_DT_RX_SHORT_READ_1) { + } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ? + MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE : + MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) { u8 data = FLD_GET(val, 15, 8); if (dsi->debug_read) - DSSDBG("\tDCS short response, 1 byte: %02x\n", data); + DSSDBG("\t%s short response, 1 byte: %02x\n", + type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : + "DCS", data); if (buflen < 1) { r = -EIO; @@ -3212,10 +3323,14 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, buf[0] = data; return 1; - } else if (dt == DSI_DT_RX_SHORT_READ_2) { + } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ? + MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE : + MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) { u16 data = FLD_GET(val, 23, 8); if (dsi->debug_read) - DSSDBG("\tDCS short response, 2 byte: %04x\n", data); + DSSDBG("\t%s short response, 2 byte: %04x\n", + type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : + "DCS", data); if (buflen < 2) { r = -EIO; @@ -3226,11 +3341,15 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, buf[1] = (data >> 8) & 0xff; return 2; - } else if (dt == DSI_DT_RX_DCS_LONG_READ) { + } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ? + MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE : + MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) { int w; int len = FLD_GET(val, 23, 8); if (dsi->debug_read) - DSSDBG("\tDCS long response, len %d\n", len); + DSSDBG("\t%s long response, len %d\n", + type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : + "DCS", len); if (len > buflen) { r = -EIO; @@ -3266,58 +3385,126 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, BUG(); err: - DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", - channel, dcs_cmd); + DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel, + type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS"); + return r; +} +int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, + u8 *buf, int buflen) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + int r; + + r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd); + if (r) + goto err; + + r = dsi_vc_send_bta_sync(dssdev, channel); + if (r) + goto err; + + r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, + DSS_DSI_CONTENT_DCS); + if (r < 0) + goto err; + + if (r != buflen) { + r = -EIO; + goto err; + } + + return 0; +err: + DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd); + return r; } EXPORT_SYMBOL(dsi_vc_dcs_read); -int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, - u8 *data) +static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, + u8 *reqdata, int reqlen, u8 *buf, int buflen) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1); + r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen); + if (r) + return r; + + r = dsi_vc_send_bta_sync(dssdev, channel); + if (r) + return r; + r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, + DSS_DSI_CONTENT_GENERIC); if (r < 0) return r; - if (r != 1) - return -EIO; + if (r != buflen) { + r = -EIO; + return r; + } return 0; } -EXPORT_SYMBOL(dsi_vc_dcs_read_1); -int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, - u8 *data1, u8 *data2) +int dsi_vc_generic_read_0(struct omap_dss_device *dssdev, int channel, u8 *buf, + int buflen) { - u8 buf[2]; int r; - r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2); + r = dsi_vc_generic_read(dssdev, channel, NULL, 0, buf, buflen); + if (r) { + DSSERR("dsi_vc_generic_read_0(ch %d) failed\n", channel); + return r; + } - if (r < 0) + return 0; +} +EXPORT_SYMBOL(dsi_vc_generic_read_0); + +int dsi_vc_generic_read_1(struct omap_dss_device *dssdev, int channel, u8 param, + u8 *buf, int buflen) +{ + int r; + + r = dsi_vc_generic_read(dssdev, channel, ¶m, 1, buf, buflen); + if (r) { + DSSERR("dsi_vc_generic_read_1(ch %d) failed\n", channel); return r; + } - if (r != 2) - return -EIO; + return 0; +} +EXPORT_SYMBOL(dsi_vc_generic_read_1); - *data1 = buf[0]; - *data2 = buf[1]; +int dsi_vc_generic_read_2(struct omap_dss_device *dssdev, int channel, + u8 param1, u8 param2, u8 *buf, int buflen) +{ + int r; + u8 reqdata[2]; + + reqdata[0] = param1; + reqdata[1] = param2; + + r = dsi_vc_generic_read(dssdev, channel, reqdata, 2, buf, buflen); + if (r) { + DSSERR("dsi_vc_generic_read_2(ch %d) failed\n", channel); + return r; + } return 0; } -EXPORT_SYMBOL(dsi_vc_dcs_read_2); +EXPORT_SYMBOL(dsi_vc_generic_read_2); int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, u16 len) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE, - len, 0); + return dsi_vc_send_short(dsidev, channel, + MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); } EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); @@ -3508,6 +3695,75 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, ticks, x4 ? " x4" : "", x16 ? " x16" : "", (total_ticks * 1000) / (fck / 1000 / 1000)); } + +static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + int num_line_buffers; + + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + unsigned line_buf_size = dsi_get_line_buf_size(dsidev); + struct omap_video_timings *timings = &dssdev->panel.timings; + /* + * Don't use line buffers if width is greater than the video + * port's line buffer size + */ + if (line_buf_size <= timings->x_res * bpp / 8) + num_line_buffers = 0; + else + num_line_buffers = 2; + } else { + /* Use maximum number of line buffers in command mode */ + num_line_buffers = 2; + } + + /* LINE_BUFFER */ + REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); +} + +static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + int de_pol = dssdev->panel.dsi_vm_data.vp_de_pol; + int hsync_pol = dssdev->panel.dsi_vm_data.vp_hsync_pol; + int vsync_pol = dssdev->panel.dsi_vm_data.vp_vsync_pol; + bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end; + bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; + u32 r; + + r = dsi_read_reg(dsidev, DSI_CTRL); + r = FLD_MOD(r, de_pol, 9, 9); /* VP_DE_POL */ + r = FLD_MOD(r, hsync_pol, 10, 10); /* VP_HSYNC_POL */ + r = FLD_MOD(r, vsync_pol, 11, 11); /* VP_VSYNC_POL */ + r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ + r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */ + r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ + r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */ + dsi_write_reg(dsidev, DSI_CTRL, r); +} + +static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode; + int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode; + int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode; + int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode; + u32 r; + + /* + * 0 = TX FIFO packets sent or LPS in corresponding blanking periods + * 1 = Long blanking packets are sent in corresponding blanking periods + */ + r = dsi_read_reg(dsidev, DSI_CTRL); + r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */ + r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */ + r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */ + r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */ + dsi_write_reg(dsidev, DSI_CTRL, r); +} + static int dsi_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -3530,7 +3786,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); - switch (dssdev->ctrl.pixel_size) { + switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) { case 16: buswidth = 0; break; @@ -3551,7 +3807,6 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/ r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */ r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ - r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */ r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { @@ -3562,6 +3817,13 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); + dsi_config_vp_num_line_buffers(dssdev); + + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_config_vp_sync_events(dssdev); + dsi_config_blanking_modes(dssdev); + } + dsi_vc_initial_config(dsidev, 0); dsi_vc_initial_config(dsidev, 1); dsi_vc_initial_config(dsidev, 2); @@ -3580,6 +3842,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) unsigned ddr_clk_pre, ddr_clk_post; unsigned enter_hs_mode_lat, exit_hs_mode_lat; unsigned ths_eot; + int ndl = dsi_get_num_data_lanes_dssdev(dssdev); u32 r; r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); @@ -3602,7 +3865,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) /* min 60ns + 52*UI */ tclk_post = ns2ddr(dsidev, 60) + 26; - ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev)); + ths_eot = DIV_ROUND_UP(4, ndl); ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare, 4); @@ -3632,162 +3895,114 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", enter_hs_mode_lat, exit_hs_mode_lat); -} - - -#define DSI_DECL_VARS \ - int __dsi_cb = 0; u32 __dsi_cv = 0; -#define DSI_FLUSH(dsidev, ch) \ - if (__dsi_cb > 0) { \ - /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \ - dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \ - __dsi_cb = __dsi_cv = 0; \ + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + /* TODO: Implement a video mode check_timings function */ + int hsa = dssdev->panel.dsi_vm_data.hsa; + int hfp = dssdev->panel.dsi_vm_data.hfp; + int hbp = dssdev->panel.dsi_vm_data.hbp; + int vsa = dssdev->panel.dsi_vm_data.vsa; + int vfp = dssdev->panel.dsi_vm_data.vfp; + int vbp = dssdev->panel.dsi_vm_data.vbp; + int window_sync = dssdev->panel.dsi_vm_data.window_sync; + bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; + struct omap_video_timings *timings = &dssdev->panel.timings; + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + int tl, t_he, width_bytes; + + t_he = hsync_end ? + ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0; + + width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8); + + /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */ + tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp + + DIV_ROUND_UP(width_bytes + 6, ndl) + hbp; + + DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp, + hfp, hsync_end ? hsa : 0, tl); + DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp, + vsa, timings->y_res); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + r = FLD_MOD(r, hbp, 11, 0); /* HBP */ + r = FLD_MOD(r, hfp, 23, 12); /* HFP */ + r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */ + dsi_write_reg(dsidev, DSI_VM_TIMING1, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING2); + r = FLD_MOD(r, vbp, 7, 0); /* VBP */ + r = FLD_MOD(r, vfp, 15, 8); /* VFP */ + r = FLD_MOD(r, vsa, 23, 16); /* VSA */ + r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */ + dsi_write_reg(dsidev, DSI_VM_TIMING2, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING3); + r = FLD_MOD(r, timings->y_res, 14, 0); /* VACT */ + r = FLD_MOD(r, tl, 31, 16); /* TL */ + dsi_write_reg(dsidev, DSI_VM_TIMING3, r); } +} -#define DSI_PUSH(dsidev, ch, data) \ - do { \ - __dsi_cv |= (data) << (__dsi_cb * 8); \ - /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \ - if (++__dsi_cb > 3) \ - DSI_FLUSH(dsidev, ch); \ - } while (0) - -static int dsi_update_screen_l4(struct omap_dss_device *dssdev, - int x, int y, int w, int h) +int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel) { - /* Note: supports only 24bit colors in 32bit container */ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int first = 1; - int fifo_stalls = 0; - int max_dsi_packet_size; - int max_data_per_packet; - int max_pixels_per_packet; - int pixels_left; - int bytespp = dssdev->ctrl.pixel_size / 8; - int scr_width; - u32 __iomem *data; - int start_offset; - int horiz_inc; - int current_x; - struct omap_overlay *ovl; - - debug_irq = 0; - - DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n", - x, y, w, h); + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + u8 data_type; + u16 word_count; - ovl = dssdev->manager->overlays[0]; - - if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U) - return -EINVAL; - - if (dssdev->ctrl.pixel_size != 24) - return -EINVAL; - - scr_width = ovl->info.screen_width; - data = ovl->info.vaddr; - - start_offset = scr_width * y + x; - horiz_inc = scr_width - w; - current_x = x; - - /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes - * in fifo */ - - /* When using CPU, max long packet size is TX buffer size */ - max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4; - - /* we seem to get better perf if we divide the tx fifo to half, - and while the other half is being sent, we fill the other half - max_dsi_packet_size /= 2; */ - - max_data_per_packet = max_dsi_packet_size - 4 - 1; - - max_pixels_per_packet = max_data_per_packet / bytespp; - - DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet); - - pixels_left = w * h; + switch (dssdev->panel.dsi_pix_fmt) { + case OMAP_DSS_DSI_FMT_RGB888: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; + break; + case OMAP_DSS_DSI_FMT_RGB666: + data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; + break; + case OMAP_DSS_DSI_FMT_RGB666_PACKED: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; + break; + case OMAP_DSS_DSI_FMT_RGB565: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; + break; + default: + BUG(); + }; - DSSDBG("total pixels %d\n", pixels_left); + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); - data += start_offset; + /* MODE, 1 = video mode */ + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); - while (pixels_left > 0) { - /* 0x2c = write_memory_start */ - /* 0x3c = write_memory_continue */ - u8 dcs_cmd = first ? 0x2c : 0x3c; - int pixels; - DSI_DECL_VARS; - first = 0; + word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); -#if 1 - /* using fifo not empty */ - /* TX_FIFO_NOT_EMPTY */ - while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) { - fifo_stalls++; - if (fifo_stalls > 0xfffff) { - DSSERR("fifo stalls overflow, pixels left %d\n", - pixels_left); - dsi_if_enable(dsidev, 0); - return -EIO; - } - udelay(1); - } -#elif 1 - /* using fifo emptiness */ - while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 < - max_dsi_packet_size) { - fifo_stalls++; - if (fifo_stalls > 0xfffff) { - DSSERR("fifo stalls overflow, pixels left %d\n", - pixels_left); - dsi_if_enable(dsidev, 0); - return -EIO; - } - } -#else - while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, - 7, 0) + 1) * 4 == 0) { - fifo_stalls++; - if (fifo_stalls > 0xfffff) { - DSSERR("fifo stalls overflow, pixels left %d\n", - pixels_left); - dsi_if_enable(dsidev, 0); - return -EIO; - } - } -#endif - pixels = min(max_pixels_per_packet, pixels_left); + dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); - pixels_left -= pixels; + dsi_vc_enable(dsidev, channel, true); + dsi_if_enable(dsidev, true); - dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE, - 1 + pixels * bytespp, 0); + dssdev->manager->enable(dssdev->manager); - DSI_PUSH(dsidev, 0, dcs_cmd); + return 0; +} +EXPORT_SYMBOL(dsi_video_mode_enable); - while (pixels-- > 0) { - u32 pix = __raw_readl(data++); +void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff); - DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff); - DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff); + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); - current_x++; - if (current_x == x+w) { - current_x = x; - data += horiz_inc; - } - } + /* MODE, 0 = command mode */ + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); - DSI_FLUSH(dsidev, 0); - } + dsi_vc_enable(dsidev, channel, true); + dsi_if_enable(dsidev, true); - return 0; + dssdev->manager->disable(dssdev->manager); } +EXPORT_SYMBOL(dsi_video_mode_disable); static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) @@ -3808,9 +4023,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", x, y, w, h); - dsi_vc_config_vp(dsidev, channel); + dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); - bytespp = dssdev->ctrl.pixel_size / 8; + bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; bytespl = w * bytespp; bytespf = bytespl * h; @@ -3831,7 +4046,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ dsi_write_reg(dsidev, DSI_VC_TE(channel), l); - dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE, + dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE, packet_len, 0); if (dsi->te_enabled) @@ -3956,11 +4171,9 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, dsi_perf_mark_setup(dsidev); - 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(dssdev->manager->id, *w, *h); - } + dss_setup_partial_planes(dssdev, x, y, w, h, + enlarge_update_area); + dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); return 0; } @@ -3982,27 +4195,16 @@ int omap_dsi_update(struct omap_dss_device *dssdev, * see rather obscure HW error happening, as DSS halts. */ BUG_ON(x % 2 == 1); - if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dsi->framedone_callback = callback; - dsi->framedone_data = data; - - dsi->update_region.x = x; - dsi->update_region.y = y; - dsi->update_region.w = w; - dsi->update_region.h = h; - dsi->update_region.device = dssdev; - - dsi_update_screen_dispc(dssdev, x, y, w, h); - } else { - int r; + dsi->framedone_callback = callback; + dsi->framedone_data = data; - r = dsi_update_screen_l4(dssdev, x, y, w, h); - if (r) - return r; + dsi->update_region.x = x; + dsi->update_region.y = y; + dsi->update_region.w = w; + dsi->update_region.h = h; + dsi->update_region.device = dssdev; - dsi_perf_show(dsidev, "L4"); - callback(0, data); - } + dsi_update_screen_dispc(dssdev, x, y, w, h); return 0; } @@ -4013,28 +4215,9 @@ EXPORT_SYMBOL(omap_dsi_update); static int dsi_display_init_dispc(struct omap_dss_device *dssdev) { int r; - u32 irq; - - irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? - DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; - r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev, - irq); - if (r) { - DSSERR("can't get FRAMEDONE irq\n"); - return r; - } - - dispc_set_lcd_display_type(dssdev->manager->id, - OMAP_DSS_LCD_DISPLAY_TFT); - - 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->manager->id, dssdev->ctrl.pixel_size); - - { + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + u32 irq; struct omap_video_timings timings = { .hsw = 1, .hfp = 1, @@ -4044,21 +4227,46 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) .vbp = 0, }; - dispc_set_lcd_timings(dssdev->manager->id, &timings); + irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? + DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; + + r = omap_dispc_register_isr(dsi_framedone_irq_callback, + (void *) dssdev, irq); + if (r) { + DSSERR("can't get FRAMEDONE irq\n"); + return r; + } + + dispc_mgr_enable_stallmode(dssdev->manager->id, true); + dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1); + + dispc_mgr_set_lcd_timings(dssdev->manager->id, &timings); + } else { + dispc_mgr_enable_stallmode(dssdev->manager->id, false); + dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0); + + dispc_mgr_set_lcd_timings(dssdev->manager->id, + &dssdev->panel.timings); } + dispc_mgr_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); + dispc_mgr_set_tft_data_lines(dssdev->manager->id, + dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)); return 0; } static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) { - u32 irq; + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + u32 irq; - irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? - DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; + irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? + DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; - omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev, - irq); + omap_dispc_unregister_isr(dsi_framedone_irq_callback, + (void *) dssdev, irq); + } } static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) @@ -4106,7 +4314,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) return r; } - r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); + r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) { DSSERR("Failed to set dispc clocks\n"); return r; @@ -4166,10 +4374,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) return 0; err3: - dsi_cio_uninit(dsidev); + dsi_cio_uninit(dssdev); err2: dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); + err1: dsi_pll_uninit(dsidev, true); err0: @@ -4195,7 +4405,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); - dsi_cio_uninit(dsidev); + dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); + dsi_cio_uninit(dssdev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -4211,6 +4422,12 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dsi->lock); + if (dssdev->manager == NULL) { + DSSERR("failed to enable display: no manager\n"); + r = -ENODEV; + goto err_start_dev; + } + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); @@ -4307,9 +4524,10 @@ int dsi_init_display(struct omap_dss_device *dssdev) DSSDBG("DSI init\n"); - /* XXX these should be figured out dynamically */ - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | - OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | + OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; + } if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4435,10 +4653,7 @@ static int dsi_get_clocks(struct platform_device *dsidev) dsi->dss_clk = clk; - if (cpu_is_omap34xx() || cpu_is_omap3630()) - clk = clk_get(&dsidev->dev, "dss2_alwon_fck"); - else - clk = clk_get(&dsidev->dev, "sys_clk"); + clk = clk_get(&dsidev->dev, "sys_clk"); if (IS_ERR(clk)) { DSSERR("can't get sys_clk\n"); clk_put(dsi->dss_clk); @@ -4462,7 +4677,7 @@ static void dsi_put_clocks(struct platform_device *dsidev) } /* DSI1 HW IP initialisation */ -static int omap_dsi1hw_probe(struct platform_device *dsidev) +static int omap_dsihw_probe(struct platform_device *dsidev) { struct omap_display_platform_data *dss_plat_data; struct omap_dss_board_info *board_info; @@ -4483,7 +4698,8 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) dss_plat_data = dsidev->dev.platform_data; board_info = dss_plat_data->board_data; - dsi->dsi_mux_pads = board_info->dsi_mux_pads; + dsi->enable_pads = board_info->dsi_enable_pads; + dsi->disable_pads = board_info->dsi_disable_pads; spin_lock_init(&dsi->irq_lock); spin_lock_init(&dsi->errors_lock); @@ -4539,7 +4755,7 @@ static int omap_dsi1hw_probe(struct platform_device *dsidev) /* DSI VCs initialization */ for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { - dsi->vc[i].mode = DSI_VC_MODE_L4; + dsi->vc[i].source = DSI_VC_SOURCE_L4; dsi->vc[i].dssdev = NULL; dsi->vc[i].vc_id = 0; } @@ -4572,7 +4788,7 @@ err_alloc: return r; } -static int omap_dsi1hw_remove(struct platform_device *dsidev) +static int omap_dsihw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -4602,10 +4818,6 @@ static int omap_dsi1hw_remove(struct platform_device *dsidev) static int dsi_runtime_suspend(struct device *dev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); - - clk_disable(dsi->dss_clk); - dispc_runtime_put(); dss_runtime_put(); @@ -4614,7 +4826,6 @@ static int dsi_runtime_suspend(struct device *dev) static int dsi_runtime_resume(struct device *dev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); int r; r = dss_runtime_get(); @@ -4625,8 +4836,6 @@ static int dsi_runtime_resume(struct device *dev) if (r) goto err_get_dispc; - clk_enable(dsi->dss_clk); - return 0; err_get_dispc: @@ -4640,11 +4849,11 @@ static const struct dev_pm_ops dsi_pm_ops = { .runtime_resume = dsi_runtime_resume, }; -static struct platform_driver omap_dsi1hw_driver = { - .probe = omap_dsi1hw_probe, - .remove = omap_dsi1hw_remove, +static struct platform_driver omap_dsihw_driver = { + .probe = omap_dsihw_probe, + .remove = omap_dsihw_remove, .driver = { - .name = "omapdss_dsi1", + .name = "omapdss_dsi", .owner = THIS_MODULE, .pm = &dsi_pm_ops, }, @@ -4652,10 +4861,10 @@ static struct platform_driver omap_dsi1hw_driver = { int dsi_init_platform_driver(void) { - return platform_driver_register(&omap_dsi1hw_driver); + return platform_driver_register(&omap_dsihw_driver); } void dsi_uninit_platform_driver(void) { - return platform_driver_unregister(&omap_dsi1hw_driver); + return platform_driver_unregister(&omap_dsihw_driver); } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 0f9c3a6..3e09726 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -639,6 +639,17 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ } +enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) +{ + enum omap_display_type displays; + + displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); + if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) + return DSS_VENC_TV_CLK; + + return REG_GET(DSS_CONTROL, 15, 15); +} + static int dss_get_clocks(void) { struct clk *clk; @@ -691,11 +702,6 @@ static void dss_put_clocks(void) clk_put(dss.dss_clk); } -struct clk *dss_get_ick(void) -{ - return clk_get(&dss.pdev->dev, "ick"); -} - int dss_runtime_get(void) { int r; @@ -824,13 +830,11 @@ static int omap_dsshw_remove(struct platform_device *pdev) static int dss_runtime_suspend(struct device *dev) { dss_save_context(); - clk_disable(dss.dss_clk); return 0; } static int dss_runtime_resume(struct device *dev) { - clk_enable(dss.dss_clk); dss_restore_context(); return 0; } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 9c94b11..6308fc5 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -97,10 +97,10 @@ extern unsigned int dss_debug; #define FLD_MOD(orig, val, start, end) \ (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) -enum omap_parallel_interface_mode { - OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */ - OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */ - OMAP_DSS_PARALLELMODE_DSI, +enum dss_io_pad_mode { + DSS_IO_PAD_MODE_RESET, + DSS_IO_PAD_MODE_RFBI, + DSS_IO_PAD_MODE_BYPASS, }; enum dss_hdmi_venc_clk_source_select { @@ -108,6 +108,11 @@ enum dss_hdmi_venc_clk_source_select { DSS_HDMI_M_PCLK = 1, }; +enum dss_dsi_content_type { + DSS_DSI_CONTENT_DCS, + DSS_DSI_CONTENT_GENERIC, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -150,16 +155,6 @@ struct dsi_clock_info { bool use_sys_clk; }; -/* HDMI PLL structure */ -struct hdmi_pll_info { - u16 regn; - u16 regm; - u32 regmf; - u16 regm2; - u16 regsd; - u16 dcofreq; -}; - struct seq_file; struct platform_device; @@ -209,9 +204,8 @@ void dss_uninit_platform_driver(void); int dss_runtime_get(void); void dss_runtime_put(void); -struct clk *dss_get_ick(void); - void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); +enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); @@ -279,6 +273,8 @@ void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, int dsi_init_display(struct omap_dss_device *display); void dsi_irq_handler(void); +u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); + unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); int dsi_pll_set_clock_div(struct platform_device *dsidev, struct dsi_clock_info *cinfo); @@ -309,6 +305,11 @@ static inline int dsi_runtime_get(struct platform_device *dsidev) static inline void dsi_runtime_put(struct platform_device *dsidev) { } +static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) +{ + WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__); + return 0; +} static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) { WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); @@ -385,90 +386,71 @@ 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(enum omap_channel channel, bool enable); - -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_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); void dispc_enable_fifomerge(bool enable); -u32 dispc_get_burst_size(enum omap_plane plane); -void dispc_enable_cpr(enum omap_channel channel, bool enable); -void dispc_set_cpr_coef(enum omap_channel channel, - struct omap_dss_cpr_coefs *coefs); - -void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr); -void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr); -void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y); -void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height); -void dispc_set_channel_out(enum omap_plane plane, - enum omap_channel channel_out); - void dispc_enable_gamma_table(bool enable); -int dispc_setup_plane(enum omap_plane plane, - u32 paddr, u16 screen_width, - u16 pos_x, u16 pos_y, - u16 width, u16 height, - u16 out_width, u16 out_height, - enum omap_color_mode color_mode, - bool ilace, - enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, - u8 global_alpha, u8 pre_mult_alpha, - enum omap_channel channel, - u32 puv_addr); - -bool dispc_go_busy(enum omap_channel channel); -void dispc_go(enum omap_channel channel); -void dispc_enable_channel(enum omap_channel channel, bool enable); -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_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); -u32 dispc_get_default_color(enum omap_channel channel); -void dispc_set_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type type, - u32 trans_key); -void dispc_get_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type *type, - u32 *trans_key); -void dispc_enable_trans_key(enum omap_channel ch, bool enable); -void dispc_enable_alpha_blending(enum omap_channel ch, bool enable); -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(enum omap_channel channel, - struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); -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(enum omap_channel channel, + + +u32 dispc_ovl_get_fifo_size(enum omap_plane plane); +u32 dispc_ovl_get_burst_size(enum omap_plane plane); +int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, + bool ilace, enum omap_channel channel, bool replication, + u32 fifo_low, u32 fifo_high); +int dispc_ovl_enable(enum omap_plane plane, bool enable); + + +void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); +void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); +void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable); +void dispc_mgr_set_cpr_coef(enum omap_channel channel, + struct omap_dss_cpr_coefs *coefs); +bool dispc_mgr_go_busy(enum omap_channel channel); +void dispc_mgr_go(enum omap_channel channel); +void dispc_mgr_enable(enum omap_channel channel, bool enable); +bool dispc_mgr_is_channel_enabled(enum omap_channel channel); +void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); +void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); +void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); +void dispc_mgr_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type); +void dispc_mgr_set_default_color(enum omap_channel channel, u32 color); +u32 dispc_mgr_get_default_color(enum omap_channel channel); +void dispc_mgr_set_trans_key(enum omap_channel ch, + enum omap_dss_trans_key_type type, + u32 trans_key); +void dispc_mgr_get_trans_key(enum omap_channel ch, + enum omap_dss_trans_key_type *type, + u32 *trans_key); +void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable); +void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable); +bool dispc_mgr_trans_key_enabled(enum omap_channel ch); +bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch); +void dispc_mgr_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings); +void dispc_mgr_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb); +unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); +unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); +int dispc_mgr_set_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); -int dispc_get_clock_div(enum omap_channel channel, +int dispc_mgr_get_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); - /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC int venc_init_platform_driver(void); void venc_uninit_platform_driver(void); void venc_dump_regs(struct seq_file *s); int venc_init_display(struct omap_dss_device *display); +unsigned long venc_get_pixel_clock(void); #else static inline int venc_init_platform_driver(void) { @@ -477,6 +459,11 @@ static inline int venc_init_platform_driver(void) static inline void venc_uninit_platform_driver(void) { } +static inline unsigned long venc_get_pixel_clock(void) +{ + WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__); + return 0; +} #endif /* HDMI */ @@ -484,6 +471,8 @@ static inline void venc_uninit_platform_driver(void) int hdmi_init_platform_driver(void); void hdmi_uninit_platform_driver(void); int hdmi_init_display(struct omap_dss_device *dssdev); +unsigned long hdmi_get_pixel_clock(void); +void hdmi_dump_regs(struct seq_file *s); #else static inline int hdmi_init_display(struct omap_dss_device *dssdev) { @@ -496,12 +485,19 @@ static inline int hdmi_init_platform_driver(void) static inline void hdmi_uninit_platform_driver(void) { } +static inline unsigned long hdmi_get_pixel_clock(void) +{ + WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__); + return 0; +} #endif int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings); +int omapdss_hdmi_read_edid(u8 *buf, int len); +bool omapdss_hdmi_detect(void); int hdmi_panel_init(void); void hdmi_panel_exit(void); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index b415c4e..b402699 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -47,6 +47,7 @@ struct omap_dss_features { const int num_ovls; const enum omap_display_type *supported_displays; const enum omap_color_mode *supported_color_modes; + const enum omap_overlay_caps *overlay_caps; const char * const *clksrc_names; const struct dss_param_range *dss_params; @@ -209,6 +210,68 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | OMAP_DSS_COLOR_RGBX32, + + /* OMAP_DSS_VIDEO3 */ + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | + OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | + OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | + OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | + OMAP_DSS_COLOR_RGBX32, +}; + +static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { + /* OMAP_DSS_GFX */ + 0, + + /* OMAP_DSS_VIDEO1 */ + OMAP_DSS_OVL_CAP_SCALE, + + /* OMAP_DSS_VIDEO2 */ + OMAP_DSS_OVL_CAP_SCALE, +}; + +static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { + /* OMAP_DSS_GFX */ + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + + /* OMAP_DSS_VIDEO1 */ + OMAP_DSS_OVL_CAP_SCALE, + + /* OMAP_DSS_VIDEO2 */ + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, +}; + +static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { + /* OMAP_DSS_GFX */ + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + + /* OMAP_DSS_VIDEO1 */ + OMAP_DSS_OVL_CAP_SCALE, + + /* OMAP_DSS_VIDEO2 */ + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, +}; + +static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { + /* OMAP_DSS_GFX */ + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | + OMAP_DSS_OVL_CAP_ZORDER, + + /* OMAP_DSS_VIDEO1 */ + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + + /* OMAP_DSS_VIDEO2 */ + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + + /* OMAP_DSS_VIDEO3 */ + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, }; static const char * const omap2_dss_clk_source_names[] = { @@ -233,32 +296,38 @@ static const char * const omap4_dss_clk_source_names[] = { static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, + [FEAT_PARAM_DSS_PCD] = { 2, 255 }, [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 }, [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 }, [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, + [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, }; static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, + [FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, + [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, }; static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, + [FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, }; /* OMAP2 DSS Features */ @@ -275,6 +344,7 @@ static const struct omap_dss_features omap2_dss_features = { .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, .supported_color_modes = omap2_dss_supported_color_modes, + .overlay_caps = omap2_dss_overlay_caps, .clksrc_names = omap2_dss_clk_source_names, .dss_params = omap2_dss_param_range, .buffer_size_unit = 1, @@ -287,18 +357,19 @@ static const struct omap_dss_features omap3430_dss_features = { .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), .has_feature = - FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC | FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD | - FEAT_FIR_COEF_V, + FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER, .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3430_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, + .overlay_caps = omap3430_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, .dss_params = omap3_dss_param_range, .buffer_size_unit = 1, @@ -310,18 +381,19 @@ static const struct omap_dss_features omap3630_dss_features = { .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), .has_feature = - FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | - FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | + FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG | FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD | - FEAT_FIR_COEF_V, + FEAT_FIR_COEF_V | FEAT_ALPHA_FIXED_ZORDER, .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3630_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, + .overlay_caps = omap3630_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, .dss_params = omap3_dss_param_range, .buffer_size_unit = 1, @@ -335,17 +407,18 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), .has_feature = - FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | - FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | + FEAT_MGR_LCD2 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | - FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V, + FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V | + FEAT_ALPHA_FREE_ZORDER, .num_mgrs = 3, - .num_ovls = 3, + .num_ovls = 4, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap4_dss_supported_color_modes, + .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, .dss_params = omap4_dss_param_range, .buffer_size_unit = 16, @@ -358,24 +431,50 @@ static const struct omap_dss_features omap4_dss_features = { .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), .has_feature = - FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | - FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | + FEAT_MGR_LCD2 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR | - FEAT_PRELOAD | FEAT_FIR_COEF_V, + FEAT_PRELOAD | FEAT_FIR_COEF_V | FEAT_ALPHA_FREE_ZORDER, .num_mgrs = 3, - .num_ovls = 3, + .num_ovls = 4, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap4_dss_supported_color_modes, + .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, .dss_params = omap4_dss_param_range, .buffer_size_unit = 16, .burst_size_unit = 16, }; +#if defined(CONFIG_OMAP4_DSS_HDMI) +/* HDMI OMAP4 Functions*/ +static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { + + .video_configure = ti_hdmi_4xxx_basic_configure, + .phy_enable = ti_hdmi_4xxx_phy_enable, + .phy_disable = ti_hdmi_4xxx_phy_disable, + .read_edid = ti_hdmi_4xxx_read_edid, + .detect = ti_hdmi_4xxx_detect, + .pll_enable = ti_hdmi_4xxx_pll_enable, + .pll_disable = ti_hdmi_4xxx_pll_disable, + .video_enable = ti_hdmi_4xxx_wp_video_start, + .dump_wrapper = ti_hdmi_4xxx_wp_dump, + .dump_core = ti_hdmi_4xxx_core_dump, + .dump_pll = ti_hdmi_4xxx_pll_dump, + .dump_phy = ti_hdmi_4xxx_phy_dump, + +}; + +void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data) +{ + if (cpu_is_omap44xx()) + ip_data->ops = &omap4_hdmi_functions; +} +#endif + /* Functions returning values related to a DSS feature */ int dss_feat_get_num_mgrs(void) { @@ -407,6 +506,11 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) return omap_current_dss_features->supported_color_modes[plane]; } +enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane) +{ + return omap_current_dss_features->overlay_caps[plane]; +} + bool dss_feat_color_mode_supported(enum omap_plane plane, enum omap_color_mode color_mode) { diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index b7398cb..6a6c05d 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -20,16 +20,17 @@ #ifndef __OMAP2_DSS_FEATURES_H #define __OMAP2_DSS_FEATURES_H +#if defined(CONFIG_OMAP4_DSS_HDMI) +#include "ti_hdmi.h" +#endif + #define MAX_DSS_MANAGERS 3 -#define MAX_DSS_OVERLAYS 3 +#define MAX_DSS_OVERLAYS 4 #define MAX_DSS_LCD_MANAGERS 2 #define MAX_NUM_DSI 2 /* 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, @@ -55,6 +56,8 @@ enum dss_feat_id { FEAT_CPR = 1 << 23, FEAT_PRELOAD = 1 << 24, FEAT_FIR_COEF_V = 1 << 25, + FEAT_ALPHA_FIXED_ZORDER = 1 << 26, + FEAT_ALPHA_FREE_ZORDER = 1 << 27, }; /* DSS register field id */ @@ -75,12 +78,14 @@ enum dss_feat_reg_field { enum dss_range_param { FEAT_PARAM_DSS_FCK, + FEAT_PARAM_DSS_PCD, FEAT_PARAM_DSIPLL_REGN, FEAT_PARAM_DSIPLL_REGM, FEAT_PARAM_DSIPLL_REGM_DISPC, FEAT_PARAM_DSIPLL_REGM_DSI, FEAT_PARAM_DSIPLL_FINT, FEAT_PARAM_DSIPLL_LPDIV, + FEAT_PARAM_DOWNSCALE, }; /* DSS Feature Functions */ @@ -90,6 +95,7 @@ unsigned long dss_feat_get_param_min(enum dss_range_param param); unsigned long dss_feat_get_param_max(enum dss_range_param param); 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); +enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, enum omap_color_mode color_mode); const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); @@ -100,4 +106,7 @@ u32 dss_feat_get_burst_size_unit(void); /* in bytes */ 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); void dss_features_init(void); +#if defined(CONFIG_OMAP4_DSS_HDMI) +void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data); +#endif #endif diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 256f27a..3262f0f 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -37,26 +37,41 @@ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) #include <sound/soc.h> #include <sound/pcm_params.h> +#include "ti_hdmi_4xxx_ip.h" #endif +#include "ti_hdmi.h" #include "dss.h" -#include "hdmi.h" #include "dss_features.h" +#define HDMI_WP 0x0 +#define HDMI_CORE_SYS 0x400 +#define HDMI_CORE_AV 0x900 +#define HDMI_PLLCTRL 0x200 +#define HDMI_PHY 0x300 + +/* HDMI EDID Length move this */ +#define HDMI_EDID_MAX_LENGTH 256 +#define EDID_TIMING_DESCRIPTOR_SIZE 0x12 +#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36 +#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80 +#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 +#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 + +#define OMAP_HDMI_TIMINGS_NB 34 + +#define HDMI_DEFAULT_REGN 16 +#define HDMI_DEFAULT_REGM2 1 + static struct { struct mutex lock; struct omap_display_platform_data *pdata; struct platform_device *pdev; - void __iomem *base_wp; /* HDMI wrapper */ + struct hdmi_ip_data ip_data; int code; int mode; - u8 edid[HDMI_EDID_MAX_LENGTH]; - u8 edid_set; - bool custom_set; - struct hdmi_config cfg; struct clk *sys_clk; - struct clk *hdmi_clk; } hdmi; /* @@ -144,30 +159,6 @@ static const int code_vesa[85] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, -1, 33}; -static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}; - -static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val) -{ - __raw_writel(val, hdmi.base_wp + idx.idx); -} - -static inline u32 hdmi_read_reg(const struct hdmi_reg idx) -{ - return __raw_readl(hdmi.base_wp + idx.idx); -} - -static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, - int b2, int b1, u32 val) -{ - u32 t = 0; - while (val != REG_GET(idx, b2, b1)) { - udelay(1); - if (t++ > 10000) - return !val; - } - return val; -} - static int hdmi_runtime_get(void) { int r; @@ -193,304 +184,7 @@ int hdmi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - return 0; -} - -static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq, - struct hdmi_pll_info *fmt, u16 sd) -{ - u32 r; - - /* PLL start always use manual mode */ - REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0); - - r = hdmi_read_reg(PLLCTRL_CFG1); - r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ - r = FLD_MOD(r, fmt->regn, 8, 1); /* CFG1_PLL_REGN */ - - hdmi_write_reg(PLLCTRL_CFG1, r); - - r = hdmi_read_reg(PLLCTRL_CFG2); - - r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ - r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ - r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ - - if (dcofreq) { - /* divider programming for frequency beyond 1000Mhz */ - REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10); - r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ - } else { - r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ - } - - hdmi_write_reg(PLLCTRL_CFG2, r); - - r = hdmi_read_reg(PLLCTRL_CFG4); - r = FLD_MOD(r, fmt->regm2, 24, 18); - r = FLD_MOD(r, fmt->regmf, 17, 0); - - hdmi_write_reg(PLLCTRL_CFG4, r); - - /* go now */ - REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0); - - /* wait for bit change */ - if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) { - DSSERR("PLL GO bit not set\n"); - return -ETIMEDOUT; - } - - /* Wait till the lock bit is set in PLL status */ - if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { - DSSWARN("cannot lock PLL\n"); - DSSWARN("CFG1 0x%x\n", - hdmi_read_reg(PLLCTRL_CFG1)); - DSSWARN("CFG2 0x%x\n", - hdmi_read_reg(PLLCTRL_CFG2)); - DSSWARN("CFG4 0x%x\n", - hdmi_read_reg(PLLCTRL_CFG4)); - return -ETIMEDOUT; - } - - DSSDBG("PLL locked!\n"); - - return 0; -} - -/* PHY_PWR_CMD */ -static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val) -{ - /* Command for power control of HDMI PHY */ - REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6); - - /* Status of the power control of HDMI PHY */ - if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) { - DSSERR("Failed to set PHY power mode to %d\n", val); - return -ETIMEDOUT; - } - - return 0; -} - -/* PLL_PWR_CMD */ -static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val) -{ - /* Command for power control of HDMI PLL */ - REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2); - - /* wait till PHY_PWR_STATUS is set */ - if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) { - DSSERR("Failed to set PHY_PWR_STATUS\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int hdmi_pll_reset(void) -{ - /* SYSRESET controlled by power FSM */ - REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3); - - /* READ 0x0 reset is in progress */ - if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) { - DSSERR("Failed to sysreset PLL\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static int hdmi_phy_init(void) -{ - u16 r = 0; - - r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON); - if (r) - return r; - - r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON); - if (r) - return r; - - /* - * Read address 0 in order to get the SCP reset done completed - * Dummy access performed to make sure reset is done - */ - hdmi_read_reg(HDMI_TXPHY_TX_CTRL); - - /* - * Write to phy address 0 to configure the clock - * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field - */ - REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); - - /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ - hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); - - /* Setup max LDO voltage */ - REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); - - /* Write to phy address 3 to change the polarity control */ - REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); - - return 0; -} - -static int hdmi_pll_program(struct hdmi_pll_info *fmt) -{ - u16 r = 0; - enum hdmi_clk_refsel refsel; - - r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); - if (r) - return r; - - r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS); - if (r) - return r; - - r = hdmi_pll_reset(); - if (r) - return r; - - refsel = HDMI_REFSEL_SYSCLK; - - r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd); - if (r) - return r; - - return 0; -} - -static void hdmi_phy_off(void) -{ - hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); -} - -static int hdmi_core_ddc_edid(u8 *pedid, int ext) -{ - u32 i, j; - char checksum = 0; - u32 offset = 0; - - /* Turn on CLK for DDC */ - REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0); - - /* - * SW HACK : Without the Delay DDC(i2c bus) reads 0 values / - * right shifted values( The behavior is not consistent and seen only - * with some TV's) - */ - usleep_range(800, 1000); - - if (!ext) { - /* Clk SCL Devices */ - REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0); - - /* HDMI_CORE_DDC_STATUS_IN_PROG */ - if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, - 4, 4, 0) != 0) { - DSSERR("Failed to program DDC\n"); - return -ETIMEDOUT; - } - - /* Clear FIFO */ - REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0); - - /* HDMI_CORE_DDC_STATUS_IN_PROG */ - if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, - 4, 4, 0) != 0) { - DSSERR("Failed to program DDC\n"); - return -ETIMEDOUT; - } - - } else { - if (ext % 2 != 0) - offset = 0x80; - } - - /* Load Segment Address Register */ - REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0); - - /* Load Slave Address Register */ - REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); - - /* Load Offset Address Register */ - REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0); - - /* Load Byte Count */ - REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); - REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); - - /* Set DDC_CMD */ - if (ext) - REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0); - else - REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0); - - /* HDMI_CORE_DDC_STATUS_BUS_LOW */ - if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) { - DSSWARN("I2C Bus Low?\n"); - return -EIO; - } - /* HDMI_CORE_DDC_STATUS_NO_ACK */ - if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) { - DSSWARN("I2C No Ack\n"); - return -EIO; - } - - i = ext * 128; - j = 0; - while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) || - (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) && - j < 128) { - - if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) { - /* FIFO not empty */ - pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0); - j++; - } - } - - for (j = 0; j < 128; j++) - checksum += pedid[j]; - - if (checksum != 0) { - DSSERR("E-EDID checksum failed!!\n"); - return -EIO; - } - - return 0; -} - -static int read_edid(u8 *pedid, u16 max_length) -{ - int r = 0, n = 0, i = 0; - int max_ext_blocks = (max_length / 128) - 1; - - r = hdmi_core_ddc_edid(pedid, 0); - if (r) { - return r; - } else { - n = pedid[0x7e]; - - /* - * README: need to comply with max_length set by the caller. - * Better implementation should be to allocate necessary - * memory to store EDID according to nb_block field found - * in first block - */ - if (n > max_ext_blocks) - n = max_ext_blocks; - - for (i = 1; i <= n; i++) { - r = hdmi_core_ddc_edid(pedid, i); - if (r) - return r; - } - } + dss_init_hdmi_ip_ops(&hdmi.ip_data); return 0; } @@ -518,7 +212,7 @@ static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) { int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0; int timing_vsync = 0, timing_hsync = 0; - struct omap_video_timings temp; + struct hdmi_video_timings temp; struct hdmi_cm cm = {-1}; DSSDBG("hdmi_get_code\n"); @@ -556,500 +250,6 @@ static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) return cm; } -static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid , - struct omap_video_timings *timings) -{ - /* X and Y resolution */ - timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) | - edid[current_descriptor_addrs + 2]); - timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) | - edid[current_descriptor_addrs + 5]); - - timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) | - edid[current_descriptor_addrs]); - - timings->pixel_clock = 10 * timings->pixel_clock; - - /* HORIZONTAL FRONT PORCH */ - timings->hfp = edid[current_descriptor_addrs + 8] | - ((edid[current_descriptor_addrs + 11] & 0xc0) << 2); - /* HORIZONTAL SYNC WIDTH */ - timings->hsw = edid[current_descriptor_addrs + 9] | - ((edid[current_descriptor_addrs + 11] & 0x30) << 4); - /* HORIZONTAL BACK PORCH */ - timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) | - edid[current_descriptor_addrs + 3]) - - (timings->hfp + timings->hsw); - /* VERTICAL FRONT PORCH */ - timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) | - ((edid[current_descriptor_addrs + 11] & 0x0f) << 2); - /* VERTICAL SYNC WIDTH */ - timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) | - ((edid[current_descriptor_addrs + 11] & 0x03) << 4); - /* VERTICAL BACK PORCH */ - timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) | - edid[current_descriptor_addrs + 6]) - - (timings->vfp + timings->vsw); - -} - -/* Description : This function gets the resolution information from EDID */ -static void get_edid_timing_data(u8 *edid) -{ - u8 count; - u16 current_descriptor_addrs; - struct hdmi_cm cm; - struct omap_video_timings edid_timings; - - /* search block 0, there are 4 DTDs arranged in priority order */ - for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) { - current_descriptor_addrs = - EDID_DESCRIPTOR_BLOCK0_ADDRESS + - count * EDID_TIMING_DESCRIPTOR_SIZE; - get_horz_vert_timing_info(current_descriptor_addrs, - edid, &edid_timings); - cm = hdmi_get_code(&edid_timings); - DSSDBG("Block0[%d] value matches code = %d , mode = %d\n", - count, cm.code, cm.mode); - if (cm.code == -1) { - continue; - } else { - hdmi.code = cm.code; - hdmi.mode = cm.mode; - DSSDBG("code = %d , mode = %d\n", - hdmi.code, hdmi.mode); - return; - } - } - if (edid[0x7e] != 0x00) { - for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR; - count++) { - current_descriptor_addrs = - EDID_DESCRIPTOR_BLOCK1_ADDRESS + - count * EDID_TIMING_DESCRIPTOR_SIZE; - get_horz_vert_timing_info(current_descriptor_addrs, - edid, &edid_timings); - cm = hdmi_get_code(&edid_timings); - DSSDBG("Block1[%d] value matches code = %d, mode = %d", - count, cm.code, cm.mode); - if (cm.code == -1) { - continue; - } else { - hdmi.code = cm.code; - hdmi.mode = cm.mode; - DSSDBG("code = %d , mode = %d\n", - hdmi.code, hdmi.mode); - return; - } - } - } - - DSSINFO("no valid timing found , falling back to VGA\n"); - hdmi.code = 4; /* setting default value of 640 480 VGA */ - hdmi.mode = HDMI_DVI; -} - -static void hdmi_read_edid(struct omap_video_timings *dp) -{ - int ret = 0, code; - - memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH); - - if (!hdmi.edid_set) - ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH); - - if (!ret) { - if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) { - /* search for timings of default resolution */ - get_edid_timing_data(hdmi.edid); - hdmi.edid_set = true; - } - } else { - DSSWARN("failed to read E-EDID\n"); - } - - if (!hdmi.edid_set) { - DSSINFO("fallback to VGA\n"); - hdmi.code = 4; /* setting default value of 640 480 VGA */ - hdmi.mode = HDMI_DVI; - } - - code = get_timings_index(); - - *dp = cea_vesa_timings[code].timings; -} - -static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, - struct hdmi_core_infoframe_avi *avi_cfg, - struct hdmi_core_packet_enable_repeat *repeat_cfg) -{ - DSSDBG("Enter hdmi_core_init\n"); - - /* video core */ - video_cfg->ip_bus_width = HDMI_INPUT_8BIT; - video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT; - video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE; - video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; - video_cfg->hdmi_dvi = HDMI_DVI; - video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; - - /* info frame */ - avi_cfg->db1_format = 0; - avi_cfg->db1_active_info = 0; - avi_cfg->db1_bar_info_dv = 0; - avi_cfg->db1_scan_info = 0; - avi_cfg->db2_colorimetry = 0; - avi_cfg->db2_aspect_ratio = 0; - avi_cfg->db2_active_fmt_ar = 0; - avi_cfg->db3_itc = 0; - avi_cfg->db3_ec = 0; - avi_cfg->db3_q_range = 0; - avi_cfg->db3_nup_scaling = 0; - avi_cfg->db4_videocode = 0; - avi_cfg->db5_pixel_repeat = 0; - avi_cfg->db6_7_line_eoftop = 0 ; - avi_cfg->db8_9_line_sofbottom = 0; - avi_cfg->db10_11_pixel_eofleft = 0; - avi_cfg->db12_13_pixel_sofright = 0; - - /* packet enable and repeat */ - repeat_cfg->audio_pkt = 0; - repeat_cfg->audio_pkt_repeat = 0; - repeat_cfg->avi_infoframe = 0; - repeat_cfg->avi_infoframe_repeat = 0; - repeat_cfg->gen_cntrl_pkt = 0; - repeat_cfg->gen_cntrl_pkt_repeat = 0; - repeat_cfg->generic_pkt = 0; - repeat_cfg->generic_pkt_repeat = 0; -} - -static void hdmi_core_powerdown_disable(void) -{ - DSSDBG("Enter hdmi_core_powerdown_disable\n"); - REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0); -} - -static void hdmi_core_swreset_release(void) -{ - DSSDBG("Enter hdmi_core_swreset_release\n"); - REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0); -} - -static void hdmi_core_swreset_assert(void) -{ - DSSDBG("Enter hdmi_core_swreset_assert\n"); - REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0); -} - -/* DSS_HDMI_CORE_VIDEO_CONFIG */ -static void hdmi_core_video_config(struct hdmi_core_video_config *cfg) -{ - u32 r = 0; - - /* sys_ctrl1 default configuration not tunable */ - r = hdmi_read_reg(HDMI_CORE_CTRL1); - r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5); - r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4); - r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2); - r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1); - hdmi_write_reg(HDMI_CORE_CTRL1, r); - - REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6); - - /* Vid_Mode */ - r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE); - - /* dither truncation configuration */ - if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) { - r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6); - r = FLD_MOD(r, 1, 5, 5); - } else { - r = FLD_MOD(r, cfg->op_dither_truc, 7, 6); - r = FLD_MOD(r, 0, 5, 5); - } - hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r); - - /* HDMI_Ctrl */ - r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL); - r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6); - r = FLD_MOD(r, cfg->pkt_mode, 5, 3); - r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0); - hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r); - - /* TMDS_CTRL */ - REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL, - cfg->tclk_sel_clkmult, 6, 5); -} - -static void hdmi_core_aux_infoframe_avi_config( - struct hdmi_core_infoframe_avi info_avi) -{ - u32 val; - char sum = 0, checksum = 0; - - sum += 0x82 + 0x002 + 0x00D; - hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082); - hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002); - hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D); - - val = (info_avi.db1_format << 5) | - (info_avi.db1_active_info << 4) | - (info_avi.db1_bar_info_dv << 2) | - (info_avi.db1_scan_info); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val); - sum += val; - - val = (info_avi.db2_colorimetry << 6) | - (info_avi.db2_aspect_ratio << 4) | - (info_avi.db2_active_fmt_ar); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val); - sum += val; - - val = (info_avi.db3_itc << 7) | - (info_avi.db3_ec << 4) | - (info_avi.db3_q_range << 2) | - (info_avi.db3_nup_scaling); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val); - sum += val; - - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode); - sum += info_avi.db4_videocode; - - val = info_avi.db5_pixel_repeat; - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val); - sum += val; - - val = info_avi.db6_7_line_eoftop & 0x00FF; - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val); - sum += val; - - val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val); - sum += val; - - val = info_avi.db8_9_line_sofbottom & 0x00FF; - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val); - sum += val; - - val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val); - sum += val; - - val = info_avi.db10_11_pixel_eofleft & 0x00FF; - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val); - sum += val; - - val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val); - sum += val; - - val = info_avi.db12_13_pixel_sofright & 0x00FF; - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val); - sum += val; - - val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); - hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val); - sum += val; - - checksum = 0x100 - sum; - hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum); -} - -static void hdmi_core_av_packet_config( - struct hdmi_core_packet_enable_repeat repeat_cfg) -{ - /* enable/repeat the infoframe */ - hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1, - (repeat_cfg.audio_pkt << 5) | - (repeat_cfg.audio_pkt_repeat << 4) | - (repeat_cfg.avi_infoframe << 1) | - (repeat_cfg.avi_infoframe_repeat)); - - /* enable/repeat the packet */ - hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2, - (repeat_cfg.gen_cntrl_pkt << 3) | - (repeat_cfg.gen_cntrl_pkt_repeat << 2) | - (repeat_cfg.generic_pkt << 1) | - (repeat_cfg.generic_pkt_repeat)); -} - -static void hdmi_wp_init(struct omap_video_timings *timings, - struct hdmi_video_format *video_fmt, - struct hdmi_video_interface *video_int) -{ - DSSDBG("Enter hdmi_wp_init\n"); - - timings->hbp = 0; - timings->hfp = 0; - timings->hsw = 0; - timings->vbp = 0; - timings->vfp = 0; - timings->vsw = 0; - - video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; - video_fmt->y_res = 0; - video_fmt->x_res = 0; - - video_int->vsp = 0; - video_int->hsp = 0; - - video_int->interlacing = 0; - video_int->tm = 0; /* HDMI_TIMING_SLAVE */ - -} - -static void hdmi_wp_video_start(bool start) -{ - REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31); -} - -static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, - struct omap_video_timings *timings, struct hdmi_config *param) -{ - DSSDBG("Enter hdmi_wp_video_init_format\n"); - - video_fmt->y_res = param->timings.timings.y_res; - video_fmt->x_res = param->timings.timings.x_res; - - timings->hbp = param->timings.timings.hbp; - timings->hfp = param->timings.timings.hfp; - timings->hsw = param->timings.timings.hsw; - timings->vbp = param->timings.timings.vbp; - timings->vfp = param->timings.timings.vfp; - timings->vsw = param->timings.timings.vsw; -} - -static void hdmi_wp_video_config_format( - struct hdmi_video_format *video_fmt) -{ - u32 l = 0; - - REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8); - - l |= FLD_VAL(video_fmt->y_res, 31, 16); - l |= FLD_VAL(video_fmt->x_res, 15, 0); - hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l); -} - -static void hdmi_wp_video_config_interface( - struct hdmi_video_interface *video_int) -{ - u32 r; - DSSDBG("Enter hdmi_wp_video_config_interface\n"); - - r = hdmi_read_reg(HDMI_WP_VIDEO_CFG); - r = FLD_MOD(r, video_int->vsp, 7, 7); - r = FLD_MOD(r, video_int->hsp, 6, 6); - r = FLD_MOD(r, video_int->interlacing, 3, 3); - r = FLD_MOD(r, video_int->tm, 1, 0); - hdmi_write_reg(HDMI_WP_VIDEO_CFG, r); -} - -static void hdmi_wp_video_config_timing( - struct omap_video_timings *timings) -{ - u32 timing_h = 0; - u32 timing_v = 0; - - DSSDBG("Enter hdmi_wp_video_config_timing\n"); - - timing_h |= FLD_VAL(timings->hbp, 31, 20); - timing_h |= FLD_VAL(timings->hfp, 19, 8); - timing_h |= FLD_VAL(timings->hsw, 7, 0); - hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h); - - timing_v |= FLD_VAL(timings->vbp, 31, 20); - timing_v |= FLD_VAL(timings->vfp, 19, 8); - timing_v |= FLD_VAL(timings->vsw, 7, 0); - hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v); -} - -static void hdmi_basic_configure(struct hdmi_config *cfg) -{ - /* HDMI */ - struct omap_video_timings video_timing; - struct hdmi_video_format video_format; - struct hdmi_video_interface video_interface; - /* HDMI core */ - struct hdmi_core_infoframe_avi avi_cfg; - struct hdmi_core_video_config v_core_cfg; - struct hdmi_core_packet_enable_repeat repeat_cfg; - - hdmi_wp_init(&video_timing, &video_format, - &video_interface); - - hdmi_core_init(&v_core_cfg, - &avi_cfg, - &repeat_cfg); - - hdmi_wp_video_init_format(&video_format, - &video_timing, cfg); - - hdmi_wp_video_config_timing(&video_timing); - - /* video config */ - video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; - - hdmi_wp_video_config_format(&video_format); - - video_interface.vsp = cfg->timings.vsync_pol; - video_interface.hsp = cfg->timings.hsync_pol; - video_interface.interlacing = cfg->interlace; - video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */ - - hdmi_wp_video_config_interface(&video_interface); - - /* - * configure core video part - * set software reset in the core - */ - hdmi_core_swreset_assert(); - - /* power down off */ - hdmi_core_powerdown_disable(); - - v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; - v_core_cfg.hdmi_dvi = cfg->cm.mode; - - hdmi_core_video_config(&v_core_cfg); - - /* release software reset in the core */ - hdmi_core_swreset_release(); - - /* - * configure packet - * info frame video see doc CEA861-D page 65 - */ - avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; - avi_cfg.db1_active_info = - HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; - avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; - avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; - avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; - avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; - avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; - avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; - avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; - avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; - avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; - avi_cfg.db4_videocode = cfg->cm.code; - avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; - avi_cfg.db6_7_line_eoftop = 0; - avi_cfg.db8_9_line_sofbottom = 0; - avi_cfg.db10_11_pixel_eofleft = 0; - avi_cfg.db12_13_pixel_sofright = 0; - - hdmi_core_aux_infoframe_avi_config(avi_cfg); - - /* enable/repeat the infoframe */ - repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; - repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; - /* wakeup */ - repeat_cfg.audio_pkt = HDMI_PACKETENABLE; - repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; - hdmi_core_av_packet_config(repeat_cfg); -} - static void update_hdmi_timings(struct hdmi_config *cfg, struct omap_video_timings *timings, int code) { @@ -1066,6 +266,12 @@ static void update_hdmi_timings(struct hdmi_config *cfg, cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol; } +unsigned long hdmi_get_pixel_clock(void) +{ + /* HDMI Pixel Clock in Mhz */ + return hdmi.ip_data.cfg.timings.timings.pixel_clock * 10000; +} + static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, struct hdmi_pll_info *pi) { @@ -1077,15 +283,23 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, * Input clock is predivided by N + 1 * out put of which is reference clk */ - pi->regn = dssdev->clocks.hdmi.regn; - refclk = clkin / (pi->regn + 1); + if (dssdev->clocks.hdmi.regn == 0) + pi->regn = HDMI_DEFAULT_REGN; + else + pi->regn = dssdev->clocks.hdmi.regn; + + refclk = clkin / pi->regn; /* * multiplier is pixel_clk/ref_clk * Multiplying by 100 to avoid fractional part removal */ pi->regm = (phy * 100 / (refclk)) / 100; - pi->regm2 = dssdev->clocks.hdmi.regm2; + + if (dssdev->clocks.hdmi.regm2 == 0) + pi->regm2 = HDMI_DEFAULT_REGM2; + else + pi->regm2 = dssdev->clocks.hdmi.regm2; /* * fractional multiplier is remainder of the difference between @@ -1100,7 +314,10 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, * is greater than 1000MHz */ pi->dcofreq = phy > 1000 * 100; - pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10; + pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10; + + /* Set the reference clock to sysclk reference */ + pi->refsel = HDMI_REFSEL_SYSCLK; DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); @@ -1109,7 +326,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, static int hdmi_power_on(struct omap_dss_device *dssdev) { int r, code = 0; - struct hdmi_pll_info pll_data; struct omap_video_timings *p; unsigned long phy; @@ -1117,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) if (r) return r; - dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); + dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); p = &dssdev->panel.timings; @@ -1125,36 +341,31 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); - if (!hdmi.custom_set) { - DSSDBG("Read EDID as no EDID is not set on poweron\n"); - hdmi_read_edid(p); - } code = get_timings_index(); - dssdev->panel.timings = cea_vesa_timings[code].timings; - update_hdmi_timings(&hdmi.cfg, p, code); + update_hdmi_timings(&hdmi.ip_data.cfg, p, code); phy = p->pixel_clock; - hdmi_compute_pll(dssdev, phy, &pll_data); + hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); - hdmi_wp_video_start(0); + hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); - /* config the PLL and PHY first */ - r = hdmi_pll_program(&pll_data); + /* config the PLL and PHY hdmi_set_pll_pwrfirst */ + r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to lock PLL\n"); goto err; } - r = hdmi_phy_init(); + r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to start PHY\n"); goto err; } - hdmi.cfg.cm.mode = hdmi.mode; - hdmi.cfg.cm.code = hdmi.code; - hdmi_basic_configure(&hdmi.cfg); + hdmi.ip_data.cfg.cm.mode = hdmi.mode; + hdmi.ip_data.cfg.cm.code = hdmi.code; + hdmi.ip_data.ops->video_configure(&hdmi.ip_data); /* Make selection of HDMI in DSS */ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); @@ -1174,9 +385,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dispc_set_digit_size(dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); - dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1); + hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); - hdmi_wp_video_start(1); + dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1); return 0; err: @@ -1186,14 +397,12 @@ err: static void hdmi_power_off(struct omap_dss_device *dssdev) { - dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); + dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); - hdmi_wp_video_start(0); - hdmi_phy_off(); - hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); + hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); + hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); + hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); hdmi_runtime_put(); - - hdmi.edid_set = 0; } int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, @@ -1203,7 +412,6 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, cm = hdmi_get_code(timings); if (cm.code == -1) { - DSSERR("Invalid timing entered\n"); return -EINVAL; } @@ -1215,12 +423,69 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) { struct hdmi_cm cm; - hdmi.custom_set = 1; cm = hdmi_get_code(&dssdev->panel.timings); hdmi.code = cm.code; hdmi.mode = cm.mode; - omapdss_hdmi_display_enable(dssdev); - hdmi.custom_set = 0; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + int r; + + hdmi_power_off(dssdev); + + r = hdmi_power_on(dssdev); + if (r) + DSSERR("failed to power on device\n"); + } +} + +void hdmi_dump_regs(struct seq_file *s) +{ + mutex_lock(&hdmi.lock); + + if (hdmi_runtime_get()) + return; + + hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); + hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); + hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s); + hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s); + + hdmi_runtime_put(); + mutex_unlock(&hdmi.lock); +} + +int omapdss_hdmi_read_edid(u8 *buf, int len) +{ + int r; + + mutex_lock(&hdmi.lock); + + r = hdmi_runtime_get(); + BUG_ON(r); + + r = hdmi.ip_data.ops->read_edid(&hdmi.ip_data, buf, len); + + hdmi_runtime_put(); + mutex_unlock(&hdmi.lock); + + return r; +} + +bool omapdss_hdmi_detect(void) +{ + int r; + + mutex_lock(&hdmi.lock); + + r = hdmi_runtime_get(); + BUG_ON(r); + + r = hdmi.ip_data.ops->detect(&hdmi.ip_data); + + hdmi_runtime_put(); + mutex_unlock(&hdmi.lock); + + return r == 1; } int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) @@ -1231,6 +496,12 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); + if (dssdev->manager == NULL) { + DSSERR("failed to enable display: no manager\n"); + r = -ENODEV; + goto err0; + } + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); @@ -1282,219 +553,9 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) -static void hdmi_wp_audio_config_format( - struct hdmi_audio_format *aud_fmt) -{ - u32 r; - - DSSDBG("Enter hdmi_wp_audio_config_format\n"); - - r = hdmi_read_reg(HDMI_WP_AUDIO_CFG); - r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); - r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); - r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); - r = FLD_MOD(r, aud_fmt->type, 4, 4); - r = FLD_MOD(r, aud_fmt->justification, 3, 3); - r = FLD_MOD(r, aud_fmt->sample_order, 2, 2); - r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1); - r = FLD_MOD(r, aud_fmt->sample_size, 0, 0); - hdmi_write_reg(HDMI_WP_AUDIO_CFG, r); -} - -static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma) -{ - u32 r; - - DSSDBG("Enter hdmi_wp_audio_config_dma\n"); - - r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2); - r = FLD_MOD(r, aud_dma->transfer_size, 15, 8); - r = FLD_MOD(r, aud_dma->block_size, 7, 0); - hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r); - - r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL); - r = FLD_MOD(r, aud_dma->mode, 9, 9); - r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0); - hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r); -} - -static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg) -{ - u32 r; - - /* audio clock recovery parameters */ - r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL); - r = FLD_MOD(r, cfg->use_mclk, 2, 2); - r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); - r = FLD_MOD(r, cfg->cts_mode, 0, 0); - hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r); - - REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); - REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); - REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); - - if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) { - REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0); - REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0); - REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); - } else { - /* - * HDMI IP uses this configuration to divide the MCLK to - * update CTS value. - */ - REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); - - /* Configure clock for audio packets */ - REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1, - cfg->aud_par_busclk, 7, 0); - REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2, - (cfg->aud_par_busclk >> 8), 7, 0); - REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3, - (cfg->aud_par_busclk >> 16), 7, 0); - } - - /* Override of SPDIF sample frequency with value in I2S_CHST4 */ - REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1); - - /* I2S parameters */ - REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0); - - r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL); - r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7); - r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); - r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); - r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); - r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); - r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); - r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); - r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); - hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r); - - r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5); - r = FLD_MOD(r, cfg->freq_sample, 7, 4); - r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); - r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); - hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r); - - REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0); - - /* Audio channels and mode parameters */ - REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1); - r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE); - r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4); - r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3); - r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); - r = FLD_MOD(r, cfg->en_spdif, 1, 1); - hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r); -} - -static void hdmi_core_audio_infoframe_config( - struct hdmi_core_infoframe_audio *info_aud) -{ - u8 val; - u8 sum = 0, checksum = 0; - - /* - * Set audio info frame type, version and length as - * described in HDMI 1.4a Section 8.2.2 specification. - * Checksum calculation is defined in Section 5.3.5. - */ - hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84); - hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01); - hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a); - sum += 0x84 + 0x001 + 0x00a; - - val = (info_aud->db1_coding_type << 4) - | (info_aud->db1_channel_count - 1); - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val); - sum += val; - - val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val); - sum += val; - - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00); - - val = info_aud->db4_channel_alloc; - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val); - sum += val; - - val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val); - sum += val; - - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00); - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00); - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00); - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00); - hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00); - checksum = 0x100 - sum; - hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum); - - /* - * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing - * is available. - */ -} - -static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts) -{ - u32 r; - u32 deep_color = 0; - u32 pclk = hdmi.cfg.timings.timings.pixel_clock; - - if (n == NULL || cts == NULL) - return -EINVAL; - /* - * Obtain current deep color configuration. This needed - * to calculate the TMDS clock based on the pixel clock. - */ - r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0); - switch (r) { - case 1: /* No deep color selected */ - deep_color = 100; - break; - case 2: /* 10-bit deep color selected */ - deep_color = 125; - break; - case 3: /* 12-bit deep color selected */ - deep_color = 150; - break; - default: - return -EINVAL; - } - - switch (sample_freq) { - case 32000: - if ((deep_color == 125) && ((pclk == 54054) - || (pclk == 74250))) - *n = 8192; - else - *n = 4096; - break; - case 44100: - *n = 6272; - break; - case 48000: - if ((deep_color == 125) && ((pclk == 54054) - || (pclk == 74250))) - *n = 8192; - else - *n = 6144; - break; - default: - *n = 0; - return -EINVAL; - } - - /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ - *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); - - return 0; -} - -static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, +static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data, + struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { @@ -1548,7 +609,7 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - err = hdmi_config_audio_acr(params_rate(params), &n, &cts); + err = hdmi_config_audio_acr(ip_data, params_rate(params), &n, &cts); if (err < 0) return err; @@ -1564,8 +625,8 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; audio_dma.fifo_threshold = 0x20; /* in number of samples */ - hdmi_wp_audio_config_dma(&audio_dma); - hdmi_wp_audio_config_format(&audio_format); + hdmi_wp_audio_config_dma(ip_data, &audio_dma); + hdmi_wp_audio_config_format(ip_data, &audio_format); /* * I2S config @@ -1609,7 +670,7 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, /* Use parallel audio interface */ core_cfg.en_parallel_aud_input = true; - hdmi_core_audio_config(&core_cfg); + hdmi_core_audio_config(ip_data, &core_cfg); /* * Configure packet @@ -1623,36 +684,10 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, aud_if_cfg.db5_downmix_inh = false; aud_if_cfg.db5_lsv = 0; - hdmi_core_audio_infoframe_config(&aud_if_cfg); + hdmi_core_audio_infoframe_config(ip_data, &aud_if_cfg); return 0; } -static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - int err = 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0); - REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31); - REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0); - REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30); - REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31); - break; - default: - err = -EINVAL; - } - return err; -} - static int hdmi_audio_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1698,15 +733,6 @@ static int hdmi_get_clocks(struct platform_device *pdev) hdmi.sys_clk = clk; - clk = clk_get(&pdev->dev, "dss_48mhz_clk"); - if (IS_ERR(clk)) { - DSSERR("can't get hdmi_clk\n"); - clk_put(hdmi.sys_clk); - return PTR_ERR(clk); - } - - hdmi.hdmi_clk = clk; - return 0; } @@ -1714,8 +740,6 @@ static void hdmi_put_clocks(void) { if (hdmi.sys_clk) clk_put(hdmi.sys_clk); - if (hdmi.hdmi_clk) - clk_put(hdmi.hdmi_clk); } /* HDMI HW IP initialisation */ @@ -1736,20 +760,26 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) } /* Base address taken from platform */ - hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem)); - if (!hdmi.base_wp) { + hdmi.ip_data.base_wp = ioremap(hdmi_mem->start, + resource_size(hdmi_mem)); + if (!hdmi.ip_data.base_wp) { DSSERR("can't ioremap WP\n"); return -ENOMEM; } r = hdmi_get_clocks(pdev); if (r) { - iounmap(hdmi.base_wp); + iounmap(hdmi.ip_data.base_wp); return r; } pm_runtime_enable(&pdev->dev); + hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS; + hdmi.ip_data.core_av_offset = HDMI_CORE_AV; + hdmi.ip_data.pll_offset = HDMI_PLLCTRL; + hdmi.ip_data.phy_offset = HDMI_PHY; + hdmi_panel_init(); #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ @@ -1779,14 +809,13 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev) hdmi_put_clocks(); - iounmap(hdmi.base_wp); + iounmap(hdmi.ip_data.base_wp); return 0; } static int hdmi_runtime_suspend(struct device *dev) { - clk_disable(hdmi.hdmi_clk); clk_disable(hdmi.sys_clk); dispc_runtime_put(); @@ -1809,7 +838,6 @@ static int hdmi_runtime_resume(struct device *dev) clk_enable(hdmi.sys_clk); - clk_enable(hdmi.hdmi_clk); return 0; diff --git a/drivers/video/omap2/dss/hdmi_omap4_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index 7d4f2bd..533d5dc 100644 --- a/drivers/video/omap2/dss/hdmi_omap4_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c @@ -1,5 +1,5 @@ /* - * hdmi_omap4_panel.c + * hdmi_panel.c * * HDMI library support functions for TI OMAP4 processors. * @@ -25,6 +25,7 @@ #include <linux/mutex.h> #include <linux/module.h> #include <video/omapdss.h> +#include <linux/slab.h> #include "dss.h" @@ -40,13 +41,7 @@ static int hdmi_panel_probe(struct omap_dss_device *dssdev) dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; - /* - * Initialize the timings to 640 * 480 - * This is only for framebuffer update not for TV timing setting - * Setting TV timing will be done only on enable - */ - dssdev->panel.timings.x_res = 640; - dssdev->panel.timings.y_res = 480; + dssdev->panel.timings = (struct omap_video_timings){640, 480, 25175, 96, 16, 48, 2 , 11, 31}; DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", dssdev->panel.timings.x_res, @@ -161,12 +156,7 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, mutex_lock(&hdmi.hdmi_lock); dssdev->panel.timings = *timings; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - /* turn the hdmi off and on to get new timings to use */ - omapdss_hdmi_display_disable(dssdev); - omapdss_hdmi_display_set_timing(dssdev); - } + omapdss_hdmi_display_set_timing(dssdev); mutex_unlock(&hdmi.hdmi_lock); } @@ -181,12 +171,54 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev, mutex_lock(&hdmi.hdmi_lock); r = omapdss_hdmi_display_check_timing(dssdev, timings); - if (r) { - DSSERR("Timing cannot be applied\n"); - goto err; + + mutex_unlock(&hdmi.hdmi_lock); + return r; +} + +static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) +{ + int r; + + mutex_lock(&hdmi.hdmi_lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + r = omapdss_hdmi_display_enable(dssdev); + if (r) + goto err; + } + + r = omapdss_hdmi_read_edid(buf, len); + + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || + dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) + omapdss_hdmi_display_disable(dssdev); +err: + mutex_unlock(&hdmi.hdmi_lock); + + return r; +} + +static bool hdmi_detect(struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&hdmi.hdmi_lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + r = omapdss_hdmi_display_enable(dssdev); + if (r) + goto err; } + + r = omapdss_hdmi_detect(); + + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || + dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) + omapdss_hdmi_display_disable(dssdev); err: mutex_unlock(&hdmi.hdmi_lock); + return r; } @@ -200,6 +232,8 @@ static struct omap_dss_driver hdmi_driver = { .get_timings = hdmi_get_timings, .set_timings = hdmi_set_timings, .check_timings = hdmi_check_timings, + .read_edid = hdmi_read_edid, + .detect = hdmi_detect, .driver = { .name = "hdmi_panel", .owner = THIS_MODULE, diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 13d72d5..6e63845 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -106,7 +106,7 @@ put_device: static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color); + return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color); } static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, @@ -116,8 +116,9 @@ static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, u32 color; int r; - if (sscanf(buf, "%d", &color) != 1) - return -EINVAL; + r = kstrtouint(buf, 0, &color); + if (r) + return r; mgr->get_manager_info(mgr, &info); @@ -184,7 +185,7 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key); + return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key); } static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, @@ -194,8 +195,9 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, u32 key_value; int r; - if (sscanf(buf, "%d", &key_value) != 1) - return -EINVAL; + r = kstrtouint(buf, 0, &key_value); + if (r) + return r; mgr->get_manager_info(mgr, &info); @@ -222,15 +224,16 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, const char *buf, size_t size) { struct omap_overlay_manager_info info; - int enable; + bool enable; int r; - if (sscanf(buf, "%d", &enable) != 1) - return -EINVAL; + r = strtobool(buf, &enable); + if (r) + return r; mgr->get_manager_info(mgr, &info); - info.trans_enabled = enable ? true : false; + info.trans_enabled = enable; r = mgr->set_manager_info(mgr, &info); if (r) @@ -246,7 +249,10 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, static ssize_t manager_alpha_blending_enabled_show( struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled); + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + mgr->info.partial_alpha_enabled); } static ssize_t manager_alpha_blending_enabled_store( @@ -254,15 +260,18 @@ static ssize_t manager_alpha_blending_enabled_store( const char *buf, size_t size) { struct omap_overlay_manager_info info; - int enable; + bool enable; int r; - if (sscanf(buf, "%d", &enable) != 1) - return -EINVAL; + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + r = strtobool(buf, &enable); + if (r) + return r; mgr->get_manager_info(mgr, &info); - info.alpha_enabled = enable ? true : false; + info.partial_alpha_enabled = enable; r = mgr->set_manager_info(mgr, &info); if (r) @@ -285,19 +294,16 @@ static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, const char *buf, size_t size) { struct omap_overlay_manager_info info; - int v; int r; bool enable; if (!dss_has_feature(FEAT_CPR)) return -ENODEV; - r = kstrtoint(buf, 0, &v); + r = strtobool(buf, &enable); if (r) return r; - enable = !!v; - mgr->get_manager_info(mgr, &info); if (info.cpr_enable == enable) @@ -586,6 +592,13 @@ static int omap_dss_unset_device(struct omap_overlay_manager *mgr) return -EINVAL; } + /* + * Don't allow currently enabled displays to have the overlay manager + * pulled out from underneath them + */ + if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) + return -EINVAL; + mgr->device->manager = NULL; mgr->device = NULL; mgr->device_changed = true; @@ -801,7 +814,7 @@ static int configure_overlay(enum omap_plane plane) { struct overlay_cache_data *c; struct manager_cache_data *mc; - struct omap_overlay_info *oi; + struct omap_overlay_info *oi, new_oi; struct omap_overlay_manager_info *mi; u16 outw, outh; u16 x, y, w, h; @@ -815,7 +828,7 @@ static int configure_overlay(enum omap_plane plane) oi = &c->info; if (!c->enabled) { - dispc_enable_plane(plane, 0); + dispc_ovl_enable(plane, 0); return 0; } @@ -843,7 +856,7 @@ static int configure_overlay(enum omap_plane plane) /* If the overlay is outside the update region, disable it */ if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, x, y, outw, outh)) { - dispc_enable_plane(plane, 0); + dispc_ovl_enable(plane, 0); return 0; } @@ -921,34 +934,27 @@ static int configure_overlay(enum omap_plane plane) } } - r = dispc_setup_plane(plane, - paddr, - oi->screen_width, - x, y, - w, h, - outw, outh, - oi->color_mode, - c->ilace, - oi->rotation_type, - oi->rotation, - oi->mirror, - oi->global_alpha, - oi->pre_mult_alpha, - c->channel, - oi->p_uv_addr); + new_oi = *oi; + + /* update new_oi members which could have been possibly updated */ + new_oi.pos_x = x; + new_oi.pos_y = y; + new_oi.width = w; + new_oi.height = h; + new_oi.out_width = outw; + new_oi.out_height = outh; + new_oi.paddr = paddr; + r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel, + c->replication, c->fifo_low, c->fifo_high); if (r) { /* this shouldn't happen */ - DSSERR("dispc_setup_plane failed for ovl %d\n", plane); - dispc_enable_plane(plane, 0); + DSSERR("dispc_ovl_setup failed for ovl %d\n", plane); + dispc_ovl_enable(plane, 0); return r; } - dispc_enable_replication(plane, c->replication); - - dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high); - - dispc_enable_plane(plane, 1); + dispc_ovl_enable(plane, 1); return 0; } @@ -962,13 +968,13 @@ static void configure_manager(enum omap_channel channel) /* picking info from the cache */ mi = &dss_cache.manager_cache[channel].info; - dispc_set_default_color(channel, mi->default_color); - dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key); - dispc_enable_trans_key(channel, mi->trans_enabled); - dispc_enable_alpha_blending(channel, mi->alpha_enabled); + dispc_mgr_set_default_color(channel, mi->default_color); + dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key); + dispc_mgr_enable_trans_key(channel, mi->trans_enabled); + dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled); if (dss_has_feature(FEAT_CPR)) { - dispc_enable_cpr(channel, mi->cpr_enable); - dispc_set_cpr_coef(channel, &mi->cpr_coefs); + dispc_mgr_enable_cpr(channel, mi->cpr_enable); + dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs); } } @@ -992,7 +998,7 @@ static int configure_dispc(void) busy = false; for (i = 0; i < num_mgrs; i++) { - mgr_busy[i] = dispc_go_busy(i); + mgr_busy[i] = dispc_mgr_go_busy(i); mgr_go[i] = false; } @@ -1053,7 +1059,7 @@ static int configure_dispc(void) * always be turned off after frame, and new settings will be * taken in to use at next update */ if (!mc->manual_update) - dispc_go(i); + dispc_mgr_go(i); } if (busy) @@ -1258,7 +1264,7 @@ static void dss_apply_irq_handler(void *data, u32 mask) u32 irq_mask; for (i = 0; i < num_mgrs; i++) - mgr_busy[i] = dispc_go_busy(i); + mgr_busy[i] = dispc_mgr_go_busy(i); spin_lock(&dss_cache.lock); @@ -1280,7 +1286,7 @@ static void dss_apply_irq_handler(void *data, u32 mask) /* re-read busy flags */ for (i = 0; i < num_mgrs; i++) - mgr_busy[i] = dispc_go_busy(i); + mgr_busy[i] = dispc_mgr_go_busy(i); /* keep running as long as there are busy managers, so that * we can collect overlay-applied information */ @@ -1326,11 +1332,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ovl = omap_dss_get_overlay(i); - if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) - continue; - oc = &dss_cache.overlay_cache[ovl->id]; + if (ovl->manager_changed) { + ovl->manager_changed = false; + ovl->info_dirty = true; + } + if (!overlay_enabled(ovl)) { if (oc->enabled) { oc->enabled = false; @@ -1375,9 +1383,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) list_for_each_entry(mgr, &manager_list, list) { struct omap_dss_device *dssdev; - if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC)) - continue; - mc = &dss_cache.manager_cache[mgr->id]; if (mgr->device_changed) { @@ -1423,9 +1428,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ovl = omap_dss_get_overlay(i); - if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) - continue; - oc = &dss_cache.overlay_cache[ovl->id]; if (!oc->enabled) @@ -1433,11 +1435,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) dssdev = ovl->manager->device; - size = dispc_get_plane_fifo_size(ovl->id); + size = dispc_ovl_get_fifo_size(ovl->id); if (use_fifomerge) size *= 3; - burst_size = dispc_get_burst_size(ovl->id); + burst_size = dispc_ovl_get_burst_size(ovl->id); switch (dssdev->type) { case OMAP_DISPLAY_TYPE_DPI: @@ -1484,12 +1486,17 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) static int dss_check_manager(struct omap_overlay_manager *mgr) { - /* OMAP supports only graphics source transparency color key and alpha - * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */ - - if (mgr->info.alpha_enabled && mgr->info.trans_enabled && - mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) - return -EINVAL; + if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { + /* + * OMAP3 supports only graphics source transparency color key + * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 + * Alpha Mode + */ + if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled + && mgr->info.trans_key_type != + OMAP_DSS_COLOR_KEY_GFX_DST) + return -EINVAL; + } return 0; } @@ -1522,13 +1529,13 @@ static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, static int dss_mgr_enable(struct omap_overlay_manager *mgr) { - dispc_enable_channel(mgr->id, 1); + dispc_mgr_enable(mgr->id, 1); return 0; } static int dss_mgr_disable(struct omap_overlay_manager *mgr) { - dispc_enable_channel(mgr->id, 0); + dispc_mgr_enable(mgr->id, 0); return 0; } @@ -1580,7 +1587,7 @@ int dss_init_overlay_managers(struct platform_device *pdev) mgr->enable = &dss_mgr_enable; mgr->disable = &dss_mgr_disable; - mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC; + mgr->caps = 0; mgr->supported_displays = dss_feat_get_supported_displays(mgr->id); @@ -1597,42 +1604,6 @@ int dss_init_overlay_managers(struct platform_device *pdev) } } -#ifdef L4_EXAMPLE - { - int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr) - { - DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name); - - return 0; - } - - struct omap_overlay_manager *mgr; - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); - - BUG_ON(mgr == NULL); - - mgr->name = "l4"; - mgr->supported_displays = - OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI; - - mgr->set_device = &omap_dss_set_device; - mgr->unset_device = &omap_dss_unset_device; - mgr->apply = &omap_dss_mgr_apply_l4; - mgr->set_manager_info = &omap_dss_mgr_set_info; - mgr->get_manager_info = &omap_dss_mgr_get_info; - - dss_overlay_setup_l4_manager(mgr); - - omap_dss_add_overlay_manager(mgr); - - r = kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "managerl4"); - - if (r) - DSSERR("failed to create sysfs file\n"); - } -#endif - return 0; } diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index c84380c..ab8e40e 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -211,16 +211,17 @@ static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, size_t size) { - int r, enable; + int r; + bool enable; struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); - r = kstrtoint(buf, 0, &enable); + r = strtobool(buf, &enable); if (r) return r; - info.enabled = !!enable; + info.enabled = enable; r = ovl->set_overlay_info(ovl, &info); if (r) @@ -248,7 +249,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, u8 alpha; struct omap_overlay_info info; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) return -ENODEV; r = kstrtou8(buf, 0, &alpha); @@ -257,14 +258,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, ovl->get_overlay_info(ovl, &info); - /* Video1 plane does not support global alpha - * to always make it 255 completely opaque - */ - if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - ovl->id == OMAP_DSS_VIDEO1) - info.global_alpha = 255; - else - info.global_alpha = alpha; + info.global_alpha = alpha; r = ovl->set_overlay_info(ovl, &info); if (r) @@ -293,20 +287,52 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, u8 alpha; struct omap_overlay_info info; + if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + return -ENODEV; + r = kstrtou8(buf, 0, &alpha); if (r) return r; 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 = alpha; + info.pre_mult_alpha = alpha; + + 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; +} + +static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder); +} + +static ssize_t overlay_zorder_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 zorder; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &zorder); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.zorder = zorder; r = ovl->set_overlay_info(ovl, &info); if (r) @@ -347,6 +373,8 @@ static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, overlay_pre_mult_alpha_show, overlay_pre_mult_alpha_store); +static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, + overlay_zorder_show, overlay_zorder_store); static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_name.attr, @@ -358,6 +386,7 @@ static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_enabled.attr, &overlay_attr_global_alpha.attr, &overlay_attr_pre_mult_alpha.attr, + &overlay_attr_zorder.attr, NULL }; @@ -407,6 +436,7 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) struct omap_overlay_info *info; u16 outw, outh; u16 dw, dh; + int i; if (!dssdev) return 0; @@ -462,6 +492,31 @@ int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) return -EINVAL; } + if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) { + if (info->zorder < 0 || info->zorder > 3) { + DSSERR("zorder out of range: %d\n", + info->zorder); + return -EINVAL; + } + /* + * Check that zorder doesn't match with zorder of any other + * overlay which is enabled and is also connected to the same + * manager + */ + for (i = 0; i < omap_dss_get_num_overlays(); i++) { + struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i); + + if (tmp_ovl->id != ovl->id && + tmp_ovl->manager == ovl->manager && + tmp_ovl->info.enabled == true && + tmp_ovl->info.zorder == info->zorder) { + DSSERR("%s and %s have same zorder: %d\n", + ovl->name, tmp_ovl->name, info->zorder); + return -EINVAL; + } + } + } + return 0; } @@ -516,6 +571,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, } ovl->manager = mgr; + ovl->manager_changed = true; /* XXX: When there is an overlay on a DSI manual update display, and * the overlay is first disabled, then moved to tv, and enabled, we @@ -529,15 +585,12 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, * Userspace workaround for this is to update the LCD after disabling * the overlay, but before moving the overlay to TV. */ - dispc_set_channel_out(ovl->id, mgr->id); return 0; } static int omap_dss_unset_manager(struct omap_overlay *ovl) { - int r; - if (!ovl->manager) { DSSERR("failed to detach overlay: manager not set\n"); return -EINVAL; @@ -548,11 +601,8 @@ static int omap_dss_unset_manager(struct omap_overlay *ovl) return -EINVAL; } - r = ovl->wait_for_go(ovl); - if (r) - return r; - ovl->manager = NULL; + ovl->manager_changed = true; return 0; } @@ -618,22 +668,29 @@ void dss_init_overlays(struct platform_device *pdev) case 0: ovl->name = "gfx"; ovl->id = OMAP_DSS_GFX; - ovl->caps = OMAP_DSS_OVL_CAP_DISPC; ovl->info.global_alpha = 255; + ovl->info.zorder = 0; break; case 1: ovl->name = "vid1"; ovl->id = OMAP_DSS_VIDEO1; - ovl->caps = OMAP_DSS_OVL_CAP_SCALE | - OMAP_DSS_OVL_CAP_DISPC; ovl->info.global_alpha = 255; + ovl->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; break; case 2: ovl->name = "vid2"; ovl->id = OMAP_DSS_VIDEO2; - ovl->caps = OMAP_DSS_OVL_CAP_SCALE | - OMAP_DSS_OVL_CAP_DISPC; ovl->info.global_alpha = 255; + ovl->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; + break; + case 3: + ovl->name = "vid3"; + ovl->id = OMAP_DSS_VIDEO3; + ovl->info.global_alpha = 255; + ovl->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; break; } @@ -643,6 +700,7 @@ void dss_init_overlays(struct platform_device *pdev) ovl->get_overlay_info = &dss_ovl_get_overlay_info; ovl->wait_for_go = &dss_ovl_wait_for_go; + ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 39f4c59..1bd3703 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -309,9 +309,9 @@ static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dispc_set_lcd_size(dssdev->manager->id, width, height); + dispc_mgr_set_lcd_size(dssdev->manager->id, width, height); - dispc_enable_channel(dssdev->manager->id, true); + dispc_mgr_enable(dssdev->manager->id, true); rfbi.framedone_callback = callback; rfbi.framedone_callback_data = data; @@ -783,10 +783,8 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, if (*w == 0 || *h == 0) return -EINVAL; - if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h, true); - dispc_set_lcd_size(dssdev->manager->id, *w, *h); - } + dss_setup_partial_planes(dssdev, x, y, w, h, true); + dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); return 0; } @@ -796,22 +794,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h, void (*callback)(void *), void *data) { - if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - rfbi_transfer_area(dssdev, w, h, callback, data); - } else { - struct omap_overlay *ovl; - void __iomem *addr; - int scr_width; - - ovl = dssdev->manager->overlays[0]; - scr_width = ovl->info.screen_width; - addr = ovl->info.vaddr; - - omap_rfbi_write_pixels(addr, scr_width, x, y, w, h); - - callback(data); - } - + rfbi_transfer_area(dssdev, w, h, callback, data); return 0; } EXPORT_SYMBOL(omap_rfbi_update); @@ -860,6 +843,11 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { int r; + if (dssdev->manager == NULL) { + DSSERR("failed to enable display: no manager\n"); + return -ENODEV; + } + r = rfbi_runtime_get(); if (r) return r; @@ -877,13 +865,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) goto err1; } - dispc_set_lcd_display_type(dssdev->manager->id, + dispc_mgr_set_lcd_display_type(dssdev->manager->id, OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(dssdev->manager->id, - OMAP_DSS_PARALLELMODE_RFBI); + dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_RFBI); + dispc_mgr_enable_stallmode(dssdev->manager->id, true); - dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); + dispc_mgr_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); rfbi_configure(dssdev->phy.rfbi.channel, dssdev->ctrl.pixel_size, @@ -952,10 +940,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev) msleep(10); - if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630()) - clk = dss_get_ick(); - else - clk = clk_get(&pdev->dev, "ick"); + clk = clk_get(&pdev->dev, "ick"); if (IS_ERR(clk)) { DSSERR("can't get ick\n"); r = PTR_ERR(clk); diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 3a688c8..695dc04 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -35,13 +35,13 @@ static struct { static void sdi_basic_init(struct omap_dss_device *dssdev) { - dispc_set_parallel_interface_mode(dssdev->manager->id, - OMAP_DSS_PARALLELMODE_BYPASS); + dispc_mgr_set_io_pad_mode(DSS_IO_PAD_MODE_BYPASS); + dispc_mgr_enable_stallmode(dssdev->manager->id, false); - dispc_set_lcd_display_type(dssdev->manager->id, + dispc_mgr_set_lcd_display_type(dssdev->manager->id, OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_tft_data_lines(dssdev->manager->id, 24); + dispc_mgr_set_tft_data_lines(dssdev->manager->id, 24); dispc_lcd_enable_signal_polarity(1); } @@ -55,6 +55,11 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) unsigned long pck; int r; + if (dssdev->manager == NULL) { + DSSERR("failed to enable display: no manager\n"); + return -ENODEV; + } + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); @@ -78,7 +83,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) /* 15.5.9.1.2 */ dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; - dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dispc_mgr_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dssdev->panel.acbi, dssdev->panel.acb); r = dss_calc_clock_div(1, t->pixel_clock * 1000, @@ -101,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dispc_set_lcd_timings(dssdev->manager->id, t); + dispc_mgr_set_lcd_timings(dssdev->manager->id, t); r = dss_set_clock_div(&dss_cinfo); if (r) goto err_set_dss_clock_div; - r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); + r = dispc_mgr_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) goto err_set_dispc_clock_div; diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h new file mode 100644 index 0000000..2c3443d --- /dev/null +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -0,0 +1,138 @@ +/* + * ti_hdmi.h + * + * HDMI driver definition for TI OMAP4, DM81xx, DM38xx Processor. + * + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.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/>. + */ + +#ifndef _TI_HDMI_H +#define _TI_HDMI_H + +struct hdmi_ip_data; + +enum hdmi_pll_pwr { + HDMI_PLLPWRCMD_ALLOFF = 0, + HDMI_PLLPWRCMD_PLLONLY = 1, + HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2, + HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3 +}; + +enum hdmi_core_hdmi_dvi { + HDMI_DVI = 0, + HDMI_HDMI = 1 +}; + +enum hdmi_clk_refsel { + HDMI_REFSEL_PCLK = 0, + HDMI_REFSEL_REF1 = 1, + HDMI_REFSEL_REF2 = 2, + HDMI_REFSEL_SYSCLK = 3 +}; + +struct hdmi_video_timings { + u16 x_res; + u16 y_res; + /* Unit: KHz */ + u32 pixel_clock; + u16 hsw; + u16 hfp; + u16 hbp; + u16 vsw; + u16 vfp; + u16 vbp; +}; + +/* HDMI timing structure */ +struct hdmi_timings { + struct hdmi_video_timings timings; + int vsync_pol; + int hsync_pol; +}; + +struct hdmi_cm { + int code; + int mode; +}; + +struct hdmi_config { + struct hdmi_timings timings; + u16 interlace; + struct hdmi_cm cm; +}; + +/* HDMI PLL structure */ +struct hdmi_pll_info { + u16 regn; + u16 regm; + u32 regmf; + u16 regm2; + u16 regsd; + u16 dcofreq; + enum hdmi_clk_refsel refsel; +}; + +struct ti_hdmi_ip_ops { + + void (*video_configure)(struct hdmi_ip_data *ip_data); + + int (*phy_enable)(struct hdmi_ip_data *ip_data); + + void (*phy_disable)(struct hdmi_ip_data *ip_data); + + int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len); + + bool (*detect)(struct hdmi_ip_data *ip_data); + + int (*pll_enable)(struct hdmi_ip_data *ip_data); + + void (*pll_disable)(struct hdmi_ip_data *ip_data); + + void (*video_enable)(struct hdmi_ip_data *ip_data, bool start); + + void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); + + void (*dump_core)(struct hdmi_ip_data *ip_data, struct seq_file *s); + + void (*dump_pll)(struct hdmi_ip_data *ip_data, struct seq_file *s); + + void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); + +}; + +struct hdmi_ip_data { + void __iomem *base_wp; /* HDMI wrapper */ + unsigned long core_sys_offset; + unsigned long core_av_offset; + unsigned long pll_offset; + unsigned long phy_offset; + const struct ti_hdmi_ip_ops *ops; + struct hdmi_config cfg; + struct hdmi_pll_info pll_data; +}; +int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); +int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); +bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start); +int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); +void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); +void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); +void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); +void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); + +#endif diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c new file mode 100644 index 0000000..e1a6ce5 --- /dev/null +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -0,0 +1,1239 @@ +/* + * ti_hdmi_4xxx_ip.c + * + * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Authors: Yong Zhi + * Mythri pk <mythripk@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/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/seq_file.h> + +#include "ti_hdmi_4xxx_ip.h" +#include "dss.h" + +static inline void hdmi_write_reg(void __iomem *base_addr, + const u16 idx, u32 val) +{ + __raw_writel(val, base_addr + idx); +} + +static inline u32 hdmi_read_reg(void __iomem *base_addr, + const u16 idx) +{ + return __raw_readl(base_addr + idx); +} + +static inline void __iomem *hdmi_wp_base(struct hdmi_ip_data *ip_data) +{ + return ip_data->base_wp; +} + +static inline void __iomem *hdmi_phy_base(struct hdmi_ip_data *ip_data) +{ + return ip_data->base_wp + ip_data->phy_offset; +} + +static inline void __iomem *hdmi_pll_base(struct hdmi_ip_data *ip_data) +{ + return ip_data->base_wp + ip_data->pll_offset; +} + +static inline void __iomem *hdmi_av_base(struct hdmi_ip_data *ip_data) +{ + return ip_data->base_wp + ip_data->core_av_offset; +} + +static inline void __iomem *hdmi_core_sys_base(struct hdmi_ip_data *ip_data) +{ + return ip_data->base_wp + ip_data->core_sys_offset; +} + +static inline int hdmi_wait_for_bit_change(void __iomem *base_addr, + const u16 idx, + int b2, int b1, u32 val) +{ + u32 t = 0; + while (val != REG_GET(base_addr, idx, b2, b1)) { + udelay(1); + if (t++ > 10000) + return !val; + } + return val; +} + +static int hdmi_pll_init(struct hdmi_ip_data *ip_data) +{ + u32 r; + void __iomem *pll_base = hdmi_pll_base(ip_data); + struct hdmi_pll_info *fmt = &ip_data->pll_data; + + /* PLL start always use manual mode */ + REG_FLD_MOD(pll_base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); + + r = hdmi_read_reg(pll_base, PLLCTRL_CFG1); + r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ + r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */ + + hdmi_write_reg(pll_base, PLLCTRL_CFG1, r); + + r = hdmi_read_reg(pll_base, PLLCTRL_CFG2); + + r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ + r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ + r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ + r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */ + + if (fmt->dcofreq) { + /* divider programming for frequency beyond 1000Mhz */ + REG_FLD_MOD(pll_base, PLLCTRL_CFG3, fmt->regsd, 17, 10); + r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ + } else { + r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ + } + + hdmi_write_reg(pll_base, PLLCTRL_CFG2, r); + + r = hdmi_read_reg(pll_base, PLLCTRL_CFG4); + r = FLD_MOD(r, fmt->regm2, 24, 18); + r = FLD_MOD(r, fmt->regmf, 17, 0); + + hdmi_write_reg(pll_base, PLLCTRL_CFG4, r); + + /* go now */ + REG_FLD_MOD(pll_base, PLLCTRL_PLL_GO, 0x1, 0, 0); + + /* wait for bit change */ + if (hdmi_wait_for_bit_change(pll_base, PLLCTRL_PLL_GO, + 0, 0, 1) != 1) { + pr_err("PLL GO bit not set\n"); + return -ETIMEDOUT; + } + + /* Wait till the lock bit is set in PLL status */ + if (hdmi_wait_for_bit_change(pll_base, + PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { + pr_err("cannot lock PLL\n"); + pr_err("CFG1 0x%x\n", + hdmi_read_reg(pll_base, PLLCTRL_CFG1)); + pr_err("CFG2 0x%x\n", + hdmi_read_reg(pll_base, PLLCTRL_CFG2)); + pr_err("CFG4 0x%x\n", + hdmi_read_reg(pll_base, PLLCTRL_CFG4)); + return -ETIMEDOUT; + } + + pr_debug("PLL locked!\n"); + + return 0; +} + +/* PHY_PWR_CMD */ +static int hdmi_set_phy_pwr(struct hdmi_ip_data *ip_data, enum hdmi_phy_pwr val) +{ + /* Command for power control of HDMI PHY */ + REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 7, 6); + + /* Status of the power control of HDMI PHY */ + if (hdmi_wait_for_bit_change(hdmi_wp_base(ip_data), + HDMI_WP_PWR_CTRL, 5, 4, val) != val) { + pr_err("Failed to set PHY power mode to %d\n", val); + return -ETIMEDOUT; + } + + return 0; +} + +/* PLL_PWR_CMD */ +static int hdmi_set_pll_pwr(struct hdmi_ip_data *ip_data, enum hdmi_pll_pwr val) +{ + /* Command for power control of HDMI PLL */ + REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 3, 2); + + /* wait till PHY_PWR_STATUS is set */ + if (hdmi_wait_for_bit_change(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, + 1, 0, val) != val) { + pr_err("Failed to set PLL_PWR_STATUS\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int hdmi_pll_reset(struct hdmi_ip_data *ip_data) +{ + /* SYSRESET controlled by power FSM */ + REG_FLD_MOD(hdmi_pll_base(ip_data), PLLCTRL_PLL_CONTROL, 0x0, 3, 3); + + /* READ 0x0 reset is in progress */ + if (hdmi_wait_for_bit_change(hdmi_pll_base(ip_data), + PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) { + pr_err("Failed to sysreset PLL\n"); + return -ETIMEDOUT; + } + + return 0; +} + +int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data) +{ + u16 r = 0; + + r = hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); + if (r) + return r; + + r = hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); + if (r) + return r; + + r = hdmi_pll_reset(ip_data); + if (r) + return r; + + r = hdmi_pll_init(ip_data); + if (r) + return r; + + return 0; +} + +void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) +{ + hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); +} + +int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) +{ + u16 r = 0; + void __iomem *phy_base = hdmi_phy_base(ip_data); + + r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); + if (r) + return r; + + r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); + if (r) + return r; + + /* + * Read address 0 in order to get the SCP reset done completed + * Dummy access performed to make sure reset is done + */ + hdmi_read_reg(phy_base, HDMI_TXPHY_TX_CTRL); + + /* + * Write to phy address 0 to configure the clock + * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field + */ + REG_FLD_MOD(phy_base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); + + /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ + hdmi_write_reg(phy_base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); + + /* Setup max LDO voltage */ + REG_FLD_MOD(phy_base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); + + /* Write to phy address 3 to change the polarity control */ + REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); + + return 0; +} + +void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) +{ + hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); +} + +static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) +{ + void __iomem *base = hdmi_core_sys_base(ip_data); + + /* Turn on CLK for DDC */ + REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0); + + /* IN_PROG */ + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) { + /* Abort transaction */ + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0); + /* IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout aborting DDC transaction\n"); + return -ETIMEDOUT; + } + } + + /* Clk SCL Devices */ + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0); + + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout starting SCL clock\n"); + return -ETIMEDOUT; + } + + /* Clear FIFO */ + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0); + + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout clearing DDC fifo\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int hdmi_core_ddc_edid(struct hdmi_ip_data *ip_data, + u8 *pedid, int ext) +{ + void __iomem *base = hdmi_core_sys_base(ip_data); + u32 i; + char checksum; + u32 offset = 0; + + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout waiting DDC to be ready\n"); + return -ETIMEDOUT; + } + + if (ext % 2 != 0) + offset = 0x80; + + /* Load Segment Address Register */ + REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0); + + /* Load Slave Address Register */ + REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); + + /* Load Offset Address Register */ + REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0); + + /* Load Byte Count */ + REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); + + /* Set DDC_CMD */ + if (ext) + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0); + else + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0); + + /* HDMI_CORE_DDC_STATUS_BUS_LOW */ + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) { + pr_err("I2C Bus Low?\n"); + return -EIO; + } + /* HDMI_CORE_DDC_STATUS_NO_ACK */ + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) { + pr_err("I2C No Ack\n"); + return -EIO; + } + + for (i = 0; i < 0x80; ++i) { + int t; + + /* IN_PROG */ + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 0) { + DSSERR("operation stopped when reading edid\n"); + return -EIO; + } + + t = 0; + /* FIFO_EMPTY */ + while (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 1) { + if (t++ > 10000) { + DSSERR("timeout reading edid\n"); + return -ETIMEDOUT; + } + udelay(1); + } + + pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0); + } + + checksum = 0; + for (i = 0; i < 0x80; ++i) + checksum += pedid[i]; + + if (checksum != 0) { + pr_err("E-EDID checksum failed!!\n"); + return -EIO; + } + + return 0; +} + +int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, + u8 *edid, int len) +{ + int r, l; + + if (len < 128) + return -EINVAL; + + r = hdmi_core_ddc_init(ip_data); + if (r) + return r; + + r = hdmi_core_ddc_edid(ip_data, edid, 0); + if (r) + return r; + + l = 128; + + if (len >= 128 * 2 && edid[0x7e] > 0) { + r = hdmi_core_ddc_edid(ip_data, edid + 0x80, 1); + if (r) + return r; + l += 128; + } + + return l; +} + +bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) +{ + int r; + + void __iomem *base = hdmi_core_sys_base(ip_data); + + /* HPD */ + r = REG_GET(base, HDMI_CORE_SYS_SYS_STAT, 1, 1); + + return r == 1; +} + +static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, + struct hdmi_core_infoframe_avi *avi_cfg, + struct hdmi_core_packet_enable_repeat *repeat_cfg) +{ + pr_debug("Enter hdmi_core_init\n"); + + /* video core */ + video_cfg->ip_bus_width = HDMI_INPUT_8BIT; + video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT; + video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE; + video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; + video_cfg->hdmi_dvi = HDMI_DVI; + video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; + + /* info frame */ + avi_cfg->db1_format = 0; + avi_cfg->db1_active_info = 0; + avi_cfg->db1_bar_info_dv = 0; + avi_cfg->db1_scan_info = 0; + avi_cfg->db2_colorimetry = 0; + avi_cfg->db2_aspect_ratio = 0; + avi_cfg->db2_active_fmt_ar = 0; + avi_cfg->db3_itc = 0; + avi_cfg->db3_ec = 0; + avi_cfg->db3_q_range = 0; + avi_cfg->db3_nup_scaling = 0; + avi_cfg->db4_videocode = 0; + avi_cfg->db5_pixel_repeat = 0; + avi_cfg->db6_7_line_eoftop = 0 ; + avi_cfg->db8_9_line_sofbottom = 0; + avi_cfg->db10_11_pixel_eofleft = 0; + avi_cfg->db12_13_pixel_sofright = 0; + + /* packet enable and repeat */ + repeat_cfg->audio_pkt = 0; + repeat_cfg->audio_pkt_repeat = 0; + repeat_cfg->avi_infoframe = 0; + repeat_cfg->avi_infoframe_repeat = 0; + repeat_cfg->gen_cntrl_pkt = 0; + repeat_cfg->gen_cntrl_pkt_repeat = 0; + repeat_cfg->generic_pkt = 0; + repeat_cfg->generic_pkt_repeat = 0; +} + +static void hdmi_core_powerdown_disable(struct hdmi_ip_data *ip_data) +{ + pr_debug("Enter hdmi_core_powerdown_disable\n"); + REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_CTRL1, 0x0, 0, 0); +} + +static void hdmi_core_swreset_release(struct hdmi_ip_data *ip_data) +{ + pr_debug("Enter hdmi_core_swreset_release\n"); + REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_SYS_SRST, 0x0, 0, 0); +} + +static void hdmi_core_swreset_assert(struct hdmi_ip_data *ip_data) +{ + pr_debug("Enter hdmi_core_swreset_assert\n"); + REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_SYS_SRST, 0x1, 0, 0); +} + +/* HDMI_CORE_VIDEO_CONFIG */ +static void hdmi_core_video_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_video_config *cfg) +{ + u32 r = 0; + void __iomem *core_sys_base = hdmi_core_sys_base(ip_data); + + /* sys_ctrl1 default configuration not tunable */ + r = hdmi_read_reg(core_sys_base, HDMI_CORE_CTRL1); + r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5); + r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4); + r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2); + r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1); + hdmi_write_reg(core_sys_base, HDMI_CORE_CTRL1, r); + + REG_FLD_MOD(core_sys_base, + HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6); + + /* Vid_Mode */ + r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE); + + /* dither truncation configuration */ + if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) { + r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6); + r = FLD_MOD(r, 1, 5, 5); + } else { + r = FLD_MOD(r, cfg->op_dither_truc, 7, 6); + r = FLD_MOD(r, 0, 5, 5); + } + hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r); + + /* HDMI_Ctrl */ + r = hdmi_read_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_HDMI_CTRL); + r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6); + r = FLD_MOD(r, cfg->pkt_mode, 5, 3); + r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0); + hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_HDMI_CTRL, r); + + /* TMDS_CTRL */ + REG_FLD_MOD(core_sys_base, + HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5); +} + +static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_infoframe_avi info_avi) +{ + u32 val; + char sum = 0, checksum = 0; + void __iomem *av_base = hdmi_av_base(ip_data); + + sum += 0x82 + 0x002 + 0x00D; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_VERS, 0x002); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_LEN, 0x00D); + + val = (info_avi.db1_format << 5) | + (info_avi.db1_active_info << 4) | + (info_avi.db1_bar_info_dv << 2) | + (info_avi.db1_scan_info); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(0), val); + sum += val; + + val = (info_avi.db2_colorimetry << 6) | + (info_avi.db2_aspect_ratio << 4) | + (info_avi.db2_active_fmt_ar); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(1), val); + sum += val; + + val = (info_avi.db3_itc << 7) | + (info_avi.db3_ec << 4) | + (info_avi.db3_q_range << 2) | + (info_avi.db3_nup_scaling); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(2), val); + sum += val; + + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(3), + info_avi.db4_videocode); + sum += info_avi.db4_videocode; + + val = info_avi.db5_pixel_repeat; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(4), val); + sum += val; + + val = info_avi.db6_7_line_eoftop & 0x00FF; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(5), val); + sum += val; + + val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(6), val); + sum += val; + + val = info_avi.db8_9_line_sofbottom & 0x00FF; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(7), val); + sum += val; + + val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(8), val); + sum += val; + + val = info_avi.db10_11_pixel_eofleft & 0x00FF; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(9), val); + sum += val; + + val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(10), val); + sum += val; + + val = info_avi.db12_13_pixel_sofright & 0x00FF; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(11), val); + sum += val; + + val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(12), val); + sum += val; + + checksum = 0x100 - sum; + hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_CHSUM, checksum); +} + +static void hdmi_core_av_packet_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_packet_enable_repeat repeat_cfg) +{ + /* enable/repeat the infoframe */ + hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_PB_CTRL1, + (repeat_cfg.audio_pkt << 5) | + (repeat_cfg.audio_pkt_repeat << 4) | + (repeat_cfg.avi_infoframe << 1) | + (repeat_cfg.avi_infoframe_repeat)); + + /* enable/repeat the packet */ + hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_PB_CTRL2, + (repeat_cfg.gen_cntrl_pkt << 3) | + (repeat_cfg.gen_cntrl_pkt_repeat << 2) | + (repeat_cfg.generic_pkt << 1) | + (repeat_cfg.generic_pkt_repeat)); +} + +static void hdmi_wp_init(struct omap_video_timings *timings, + struct hdmi_video_format *video_fmt, + struct hdmi_video_interface *video_int) +{ + pr_debug("Enter hdmi_wp_init\n"); + + timings->hbp = 0; + timings->hfp = 0; + timings->hsw = 0; + timings->vbp = 0; + timings->vfp = 0; + timings->vsw = 0; + + video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; + video_fmt->y_res = 0; + video_fmt->x_res = 0; + + video_int->vsp = 0; + video_int->hsp = 0; + + video_int->interlacing = 0; + video_int->tm = 0; /* HDMI_TIMING_SLAVE */ + +} + +void ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data, bool start) +{ + REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, start, 31, 31); +} + +static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, + struct omap_video_timings *timings, struct hdmi_config *param) +{ + pr_debug("Enter hdmi_wp_video_init_format\n"); + + video_fmt->y_res = param->timings.timings.y_res; + video_fmt->x_res = param->timings.timings.x_res; + + timings->hbp = param->timings.timings.hbp; + timings->hfp = param->timings.timings.hfp; + timings->hsw = param->timings.timings.hsw; + timings->vbp = param->timings.timings.vbp; + timings->vfp = param->timings.timings.vfp; + timings->vsw = param->timings.timings.vsw; +} + +static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data, + struct hdmi_video_format *video_fmt) +{ + u32 l = 0; + + REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, + video_fmt->packing_mode, 10, 8); + + l |= FLD_VAL(video_fmt->y_res, 31, 16); + l |= FLD_VAL(video_fmt->x_res, 15, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_SIZE, l); +} + +static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data, + struct hdmi_video_interface *video_int) +{ + u32 r; + pr_debug("Enter hdmi_wp_video_config_interface\n"); + + r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG); + r = FLD_MOD(r, video_int->vsp, 7, 7); + r = FLD_MOD(r, video_int->hsp, 6, 6); + r = FLD_MOD(r, video_int->interlacing, 3, 3); + r = FLD_MOD(r, video_int->tm, 1, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r); +} + +static void hdmi_wp_video_config_timing(struct hdmi_ip_data *ip_data, + struct omap_video_timings *timings) +{ + u32 timing_h = 0; + u32 timing_v = 0; + + pr_debug("Enter hdmi_wp_video_config_timing\n"); + + timing_h |= FLD_VAL(timings->hbp, 31, 20); + timing_h |= FLD_VAL(timings->hfp, 19, 8); + timing_h |= FLD_VAL(timings->hsw, 7, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_TIMING_H, timing_h); + + timing_v |= FLD_VAL(timings->vbp, 31, 20); + timing_v |= FLD_VAL(timings->vfp, 19, 8); + timing_v |= FLD_VAL(timings->vsw, 7, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_TIMING_V, timing_v); +} + +void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data) +{ + /* HDMI */ + struct omap_video_timings video_timing; + struct hdmi_video_format video_format; + struct hdmi_video_interface video_interface; + /* HDMI core */ + struct hdmi_core_infoframe_avi avi_cfg; + struct hdmi_core_video_config v_core_cfg; + struct hdmi_core_packet_enable_repeat repeat_cfg; + struct hdmi_config *cfg = &ip_data->cfg; + + hdmi_wp_init(&video_timing, &video_format, + &video_interface); + + hdmi_core_init(&v_core_cfg, + &avi_cfg, + &repeat_cfg); + + hdmi_wp_video_init_format(&video_format, &video_timing, cfg); + + hdmi_wp_video_config_timing(ip_data, &video_timing); + + /* video config */ + video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; + + hdmi_wp_video_config_format(ip_data, &video_format); + + video_interface.vsp = cfg->timings.vsync_pol; + video_interface.hsp = cfg->timings.hsync_pol; + video_interface.interlacing = cfg->interlace; + video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */ + + hdmi_wp_video_config_interface(ip_data, &video_interface); + + /* + * configure core video part + * set software reset in the core + */ + hdmi_core_swreset_assert(ip_data); + + /* power down off */ + hdmi_core_powerdown_disable(ip_data); + + v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; + v_core_cfg.hdmi_dvi = cfg->cm.mode; + + hdmi_core_video_config(ip_data, &v_core_cfg); + + /* release software reset in the core */ + hdmi_core_swreset_release(ip_data); + + /* + * configure packet + * info frame video see doc CEA861-D page 65 + */ + avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; + avi_cfg.db1_active_info = + HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; + avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; + avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; + avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; + avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; + avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; + avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; + avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; + avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; + avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; + avi_cfg.db4_videocode = cfg->cm.code; + avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; + avi_cfg.db6_7_line_eoftop = 0; + avi_cfg.db8_9_line_sofbottom = 0; + avi_cfg.db10_11_pixel_eofleft = 0; + avi_cfg.db12_13_pixel_sofright = 0; + + hdmi_core_aux_infoframe_avi_config(ip_data, avi_cfg); + + /* enable/repeat the infoframe */ + repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; + repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; + /* wakeup */ + repeat_cfg.audio_pkt = HDMI_PACKETENABLE; + repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; + hdmi_core_av_packet_config(ip_data, repeat_cfg); +} + +void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) +{ +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r,\ + hdmi_read_reg(hdmi_wp_base(ip_data), r)) + + DUMPREG(HDMI_WP_REVISION); + DUMPREG(HDMI_WP_SYSCONFIG); + DUMPREG(HDMI_WP_IRQSTATUS_RAW); + DUMPREG(HDMI_WP_IRQSTATUS); + DUMPREG(HDMI_WP_PWR_CTRL); + DUMPREG(HDMI_WP_IRQENABLE_SET); + DUMPREG(HDMI_WP_VIDEO_CFG); + DUMPREG(HDMI_WP_VIDEO_SIZE); + DUMPREG(HDMI_WP_VIDEO_TIMING_H); + DUMPREG(HDMI_WP_VIDEO_TIMING_V); + DUMPREG(HDMI_WP_WP_CLK); + DUMPREG(HDMI_WP_AUDIO_CFG); + DUMPREG(HDMI_WP_AUDIO_CFG2); + DUMPREG(HDMI_WP_AUDIO_CTRL); + DUMPREG(HDMI_WP_AUDIO_DATA); +} + +void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) +{ +#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ + hdmi_read_reg(hdmi_pll_base(ip_data), r)) + + DUMPPLL(PLLCTRL_PLL_CONTROL); + DUMPPLL(PLLCTRL_PLL_STATUS); + DUMPPLL(PLLCTRL_PLL_GO); + DUMPPLL(PLLCTRL_CFG1); + DUMPPLL(PLLCTRL_CFG2); + DUMPPLL(PLLCTRL_CFG3); + DUMPPLL(PLLCTRL_CFG4); +} + +void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) +{ + int i; + +#define CORE_REG(i, name) name(i) +#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\ + hdmi_read_reg(hdmi_pll_base(ip_data), r)) +#define DUMPCOREAV(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ + (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \ + hdmi_read_reg(hdmi_pll_base(ip_data), CORE_REG(i, r))) + + DUMPCORE(HDMI_CORE_SYS_VND_IDL); + DUMPCORE(HDMI_CORE_SYS_DEV_IDL); + DUMPCORE(HDMI_CORE_SYS_DEV_IDH); + DUMPCORE(HDMI_CORE_SYS_DEV_REV); + DUMPCORE(HDMI_CORE_SYS_SRST); + DUMPCORE(HDMI_CORE_CTRL1); + DUMPCORE(HDMI_CORE_SYS_SYS_STAT); + DUMPCORE(HDMI_CORE_SYS_VID_ACEN); + DUMPCORE(HDMI_CORE_SYS_VID_MODE); + DUMPCORE(HDMI_CORE_SYS_INTR_STATE); + DUMPCORE(HDMI_CORE_SYS_INTR1); + DUMPCORE(HDMI_CORE_SYS_INTR2); + DUMPCORE(HDMI_CORE_SYS_INTR3); + DUMPCORE(HDMI_CORE_SYS_INTR4); + DUMPCORE(HDMI_CORE_SYS_UMASK1); + DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL); + DUMPCORE(HDMI_CORE_SYS_DE_DLY); + DUMPCORE(HDMI_CORE_SYS_DE_CTRL); + DUMPCORE(HDMI_CORE_SYS_DE_TOP); + DUMPCORE(HDMI_CORE_SYS_DE_CNTL); + DUMPCORE(HDMI_CORE_SYS_DE_CNTH); + DUMPCORE(HDMI_CORE_SYS_DE_LINL); + DUMPCORE(HDMI_CORE_SYS_DE_LINH_1); + + DUMPCORE(HDMI_CORE_DDC_CMD); + DUMPCORE(HDMI_CORE_DDC_STATUS); + DUMPCORE(HDMI_CORE_DDC_ADDR); + DUMPCORE(HDMI_CORE_DDC_OFFSET); + DUMPCORE(HDMI_CORE_DDC_COUNT1); + DUMPCORE(HDMI_CORE_DDC_COUNT2); + DUMPCORE(HDMI_CORE_DDC_DATA); + DUMPCORE(HDMI_CORE_DDC_SEGM); + + DUMPCORE(HDMI_CORE_AV_HDMI_CTRL); + DUMPCORE(HDMI_CORE_AV_DPD); + DUMPCORE(HDMI_CORE_AV_PB_CTRL1); + DUMPCORE(HDMI_CORE_AV_PB_CTRL2); + DUMPCORE(HDMI_CORE_AV_AVI_TYPE); + DUMPCORE(HDMI_CORE_AV_AVI_VERS); + DUMPCORE(HDMI_CORE_AV_AVI_LEN); + DUMPCORE(HDMI_CORE_AV_AVI_CHSUM); + + for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++) + DUMPCOREAV(i, HDMI_CORE_AV_AVI_DBYTE); + + for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++) + DUMPCOREAV(i, HDMI_CORE_AV_SPD_DBYTE); + + for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++) + DUMPCOREAV(i, HDMI_CORE_AV_AUD_DBYTE); + + for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++) + DUMPCOREAV(i, HDMI_CORE_AV_MPEG_DBYTE); + + for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++) + DUMPCOREAV(i, HDMI_CORE_AV_GEN_DBYTE); + + for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++) + DUMPCOREAV(i, HDMI_CORE_AV_GEN2_DBYTE); + + DUMPCORE(HDMI_CORE_AV_ACR_CTRL); + DUMPCORE(HDMI_CORE_AV_FREQ_SVAL); + DUMPCORE(HDMI_CORE_AV_N_SVAL1); + DUMPCORE(HDMI_CORE_AV_N_SVAL2); + DUMPCORE(HDMI_CORE_AV_N_SVAL3); + DUMPCORE(HDMI_CORE_AV_CTS_SVAL1); + DUMPCORE(HDMI_CORE_AV_CTS_SVAL2); + DUMPCORE(HDMI_CORE_AV_CTS_SVAL3); + DUMPCORE(HDMI_CORE_AV_CTS_HVAL1); + DUMPCORE(HDMI_CORE_AV_CTS_HVAL2); + DUMPCORE(HDMI_CORE_AV_CTS_HVAL3); + DUMPCORE(HDMI_CORE_AV_AUD_MODE); + DUMPCORE(HDMI_CORE_AV_SPDIF_CTRL); + DUMPCORE(HDMI_CORE_AV_HW_SPDIF_FS); + DUMPCORE(HDMI_CORE_AV_SWAP_I2S); + DUMPCORE(HDMI_CORE_AV_SPDIF_ERTH); + DUMPCORE(HDMI_CORE_AV_I2S_IN_MAP); + DUMPCORE(HDMI_CORE_AV_I2S_IN_CTRL); + DUMPCORE(HDMI_CORE_AV_I2S_CHST0); + DUMPCORE(HDMI_CORE_AV_I2S_CHST1); + DUMPCORE(HDMI_CORE_AV_I2S_CHST2); + DUMPCORE(HDMI_CORE_AV_I2S_CHST4); + DUMPCORE(HDMI_CORE_AV_I2S_CHST5); + DUMPCORE(HDMI_CORE_AV_ASRC); + DUMPCORE(HDMI_CORE_AV_I2S_IN_LEN); + DUMPCORE(HDMI_CORE_AV_HDMI_CTRL); + DUMPCORE(HDMI_CORE_AV_AUDO_TXSTAT); + DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_1); + DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_2); + DUMPCORE(HDMI_CORE_AV_AUD_PAR_BUSCLK_3); + DUMPCORE(HDMI_CORE_AV_TEST_TXCTRL); + DUMPCORE(HDMI_CORE_AV_DPD); + DUMPCORE(HDMI_CORE_AV_PB_CTRL1); + DUMPCORE(HDMI_CORE_AV_PB_CTRL2); + DUMPCORE(HDMI_CORE_AV_AVI_TYPE); + DUMPCORE(HDMI_CORE_AV_AVI_VERS); + DUMPCORE(HDMI_CORE_AV_AVI_LEN); + DUMPCORE(HDMI_CORE_AV_AVI_CHSUM); + DUMPCORE(HDMI_CORE_AV_SPD_TYPE); + DUMPCORE(HDMI_CORE_AV_SPD_VERS); + DUMPCORE(HDMI_CORE_AV_SPD_LEN); + DUMPCORE(HDMI_CORE_AV_SPD_CHSUM); + DUMPCORE(HDMI_CORE_AV_AUDIO_TYPE); + DUMPCORE(HDMI_CORE_AV_AUDIO_VERS); + DUMPCORE(HDMI_CORE_AV_AUDIO_LEN); + DUMPCORE(HDMI_CORE_AV_AUDIO_CHSUM); + DUMPCORE(HDMI_CORE_AV_MPEG_TYPE); + DUMPCORE(HDMI_CORE_AV_MPEG_VERS); + DUMPCORE(HDMI_CORE_AV_MPEG_LEN); + DUMPCORE(HDMI_CORE_AV_MPEG_CHSUM); + DUMPCORE(HDMI_CORE_AV_CP_BYTE1); + DUMPCORE(HDMI_CORE_AV_CEC_ADDR_ID); +} + +void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) +{ +#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\ + hdmi_read_reg(hdmi_phy_base(ip_data), r)) + + DUMPPHY(HDMI_TXPHY_TX_CTRL); + DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL); + DUMPPHY(HDMI_TXPHY_POWER_CTRL); + DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); +} + +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, + struct hdmi_audio_format *aud_fmt) +{ + u32 r; + + DSSDBG("Enter hdmi_wp_audio_config_format\n"); + + r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG); + r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); + r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); + r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); + r = FLD_MOD(r, aud_fmt->type, 4, 4); + r = FLD_MOD(r, aud_fmt->justification, 3, 3); + r = FLD_MOD(r, aud_fmt->sample_order, 2, 2); + r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1); + r = FLD_MOD(r, aud_fmt->sample_size, 0, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); +} + +void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, + struct hdmi_audio_dma *aud_dma) +{ + u32 r; + + DSSDBG("Enter hdmi_wp_audio_config_dma\n"); + + r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG2); + r = FLD_MOD(r, aud_dma->transfer_size, 15, 8); + r = FLD_MOD(r, aud_dma->block_size, 7, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG2, r); + + r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL); + r = FLD_MOD(r, aud_dma->mode, 9, 9); + r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0); + hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); +} + +void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_audio_config *cfg) +{ + u32 r; + void __iomem *av_base = hdmi_av_base(ip_data); + + /* audio clock recovery parameters */ + r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL); + r = FLD_MOD(r, cfg->use_mclk, 2, 2); + r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); + r = FLD_MOD(r, cfg->cts_mode, 0, 0); + hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r); + + REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); + REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); + REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); + + if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) { + REG_FLD_MOD(av_base, HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0); + REG_FLD_MOD(av_base, + HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0); + REG_FLD_MOD(av_base, + HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); + } else { + /* + * HDMI IP uses this configuration to divide the MCLK to + * update CTS value. + */ + REG_FLD_MOD(av_base, + HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); + + /* Configure clock for audio packets */ + REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1, + cfg->aud_par_busclk, 7, 0); + REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2, + (cfg->aud_par_busclk >> 8), 7, 0); + REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_3, + (cfg->aud_par_busclk >> 16), 7, 0); + } + + /* Override of SPDIF sample frequency with value in I2S_CHST4 */ + REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, + cfg->fs_override, 1, 1); + + /* I2S parameters */ + REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_CHST4, + cfg->freq_sample, 3, 0); + + r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL); + r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7); + r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); + r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); + r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); + r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); + r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); + r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); + r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); + hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r); + + r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_CHST5); + r = FLD_MOD(r, cfg->freq_sample, 7, 4); + r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); + r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); + hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, r); + + REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN, + cfg->i2s_cfg.in_length_bits, 3, 0); + + /* Audio channels and mode parameters */ + REG_FLD_MOD(av_base, HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1); + r = hdmi_read_reg(av_base, HDMI_CORE_AV_AUD_MODE); + r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4); + r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3); + r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); + r = FLD_MOD(r, cfg->en_spdif, 1, 1); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); +} + +void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_infoframe_audio *info_aud) +{ + u8 val; + u8 sum = 0, checksum = 0; + void __iomem *av_base = hdmi_av_base(ip_data); + + /* + * Set audio info frame type, version and length as + * described in HDMI 1.4a Section 8.2.2 specification. + * Checksum calculation is defined in Section 5.3.5. + */ + hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_TYPE, 0x84); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_VERS, 0x01); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a); + sum += 0x84 + 0x001 + 0x00a; + + val = (info_aud->db1_coding_type << 4) + | (info_aud->db1_channel_count - 1); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), val); + sum += val; + + val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), val); + sum += val; + + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), 0x00); + + val = info_aud->db4_channel_alloc; + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), val); + sum += val; + + val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), val); + sum += val; + + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(7), 0x00); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(8), 0x00); + hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(9), 0x00); + + checksum = 0x100 - sum; + hdmi_write_reg(av_base, + HDMI_CORE_AV_AUDIO_CHSUM, checksum); + + /* + * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing + * is available. + */ +} + +int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, + u32 sample_freq, u32 *n, u32 *cts) +{ + u32 r; + u32 deep_color = 0; + u32 pclk = ip_data->cfg.timings.timings.pixel_clock; + + if (n == NULL || cts == NULL) + return -EINVAL; + /* + * Obtain current deep color configuration. This needed + * to calculate the TMDS clock based on the pixel clock. + */ + r = REG_GET(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, 1, 0); + switch (r) { + case 1: /* No deep color selected */ + deep_color = 100; + break; + case 2: /* 10-bit deep color selected */ + deep_color = 125; + break; + case 3: /* 12-bit deep color selected */ + deep_color = 150; + break; + default: + return -EINVAL; + } + + switch (sample_freq) { + case 32000: + if ((deep_color == 125) && ((pclk == 54054) + || (pclk == 74250))) + *n = 8192; + else + *n = 4096; + break; + case 44100: + *n = 6272; + break; + case 48000: + if ((deep_color == 125) && ((pclk == 54054) + || (pclk == 74250))) + *n = 8192; + else + *n = 6144; + break; + default: + *n = 0; + return -EINVAL; + } + + /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ + *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); + + return 0; +} + +int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, + struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int err = 0; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + REG_FLD_MOD(hdmi_av_base(ip_data), + HDMI_CORE_AV_AUD_MODE, 1, 0, 0); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, 1, 31, 31); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, 1, 30, 30); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + REG_FLD_MOD(hdmi_av_base(ip_data), + HDMI_CORE_AV_AUD_MODE, 0, 0, 0); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, 0, 30, 30); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, 0, 31, 31); + break; + default: + err = -EINVAL; + } + return err; +} +#endif diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index c885f9c..2040956 100644 --- a/drivers/video/omap2/dss/hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h @@ -1,7 +1,7 @@ /* - * hdmi.h + * ti_hdmi_4xxx_ip.h * - * HDMI driver definition for TI OMAP4 processors. + * HDMI header definition for DM81xx, DM38xx, TI OMAP4 etc processors. * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ * @@ -18,202 +18,177 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _OMAP4_DSS_HDMI_H_ -#define _OMAP4_DSS_HDMI_H_ +#ifndef _HDMI_TI_4xxx_H_ +#define _HDMI_TI_4xxx_H_ #include <linux/string.h> #include <video/omapdss.h> - -#define HDMI_WP 0x0 -#define HDMI_CORE_SYS 0x400 -#define HDMI_CORE_AV 0x900 -#define HDMI_PLLCTRL 0x200 -#define HDMI_PHY 0x300 - -struct hdmi_reg { u16 idx; }; - -#define HDMI_REG(idx) ((const struct hdmi_reg) { idx }) +#include "ti_hdmi.h" +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +#include <sound/soc.h> +#include <sound/pcm_params.h> +#endif /* HDMI Wrapper */ -#define HDMI_WP_REG(idx) HDMI_REG(HDMI_WP + idx) - -#define HDMI_WP_REVISION HDMI_WP_REG(0x0) -#define HDMI_WP_SYSCONFIG HDMI_WP_REG(0x10) -#define HDMI_WP_IRQSTATUS_RAW HDMI_WP_REG(0x24) -#define HDMI_WP_IRQSTATUS HDMI_WP_REG(0x28) -#define HDMI_WP_PWR_CTRL HDMI_WP_REG(0x40) -#define HDMI_WP_IRQENABLE_SET HDMI_WP_REG(0x2C) -#define HDMI_WP_VIDEO_CFG HDMI_WP_REG(0x50) -#define HDMI_WP_VIDEO_SIZE HDMI_WP_REG(0x60) -#define HDMI_WP_VIDEO_TIMING_H HDMI_WP_REG(0x68) -#define HDMI_WP_VIDEO_TIMING_V HDMI_WP_REG(0x6C) -#define HDMI_WP_WP_CLK HDMI_WP_REG(0x70) -#define HDMI_WP_AUDIO_CFG HDMI_WP_REG(0x80) -#define HDMI_WP_AUDIO_CFG2 HDMI_WP_REG(0x84) -#define HDMI_WP_AUDIO_CTRL HDMI_WP_REG(0x88) -#define HDMI_WP_AUDIO_DATA HDMI_WP_REG(0x8C) + +#define HDMI_WP_REVISION 0x0 +#define HDMI_WP_SYSCONFIG 0x10 +#define HDMI_WP_IRQSTATUS_RAW 0x24 +#define HDMI_WP_IRQSTATUS 0x28 +#define HDMI_WP_PWR_CTRL 0x40 +#define HDMI_WP_IRQENABLE_SET 0x2C +#define HDMI_WP_VIDEO_CFG 0x50 +#define HDMI_WP_VIDEO_SIZE 0x60 +#define HDMI_WP_VIDEO_TIMING_H 0x68 +#define HDMI_WP_VIDEO_TIMING_V 0x6C +#define HDMI_WP_WP_CLK 0x70 +#define HDMI_WP_AUDIO_CFG 0x80 +#define HDMI_WP_AUDIO_CFG2 0x84 +#define HDMI_WP_AUDIO_CTRL 0x88 +#define HDMI_WP_AUDIO_DATA 0x8C /* HDMI IP Core System */ -#define HDMI_CORE_SYS_REG(idx) HDMI_REG(HDMI_CORE_SYS + idx) - -#define HDMI_CORE_SYS_VND_IDL HDMI_CORE_SYS_REG(0x0) -#define HDMI_CORE_SYS_DEV_IDL HDMI_CORE_SYS_REG(0x8) -#define HDMI_CORE_SYS_DEV_IDH HDMI_CORE_SYS_REG(0xC) -#define HDMI_CORE_SYS_DEV_REV HDMI_CORE_SYS_REG(0x10) -#define HDMI_CORE_SYS_SRST HDMI_CORE_SYS_REG(0x14) -#define HDMI_CORE_CTRL1 HDMI_CORE_SYS_REG(0x20) -#define HDMI_CORE_SYS_SYS_STAT HDMI_CORE_SYS_REG(0x24) -#define HDMI_CORE_SYS_VID_ACEN HDMI_CORE_SYS_REG(0x124) -#define HDMI_CORE_SYS_VID_MODE HDMI_CORE_SYS_REG(0x128) -#define HDMI_CORE_SYS_INTR_STATE HDMI_CORE_SYS_REG(0x1C0) -#define HDMI_CORE_SYS_INTR1 HDMI_CORE_SYS_REG(0x1C4) -#define HDMI_CORE_SYS_INTR2 HDMI_CORE_SYS_REG(0x1C8) -#define HDMI_CORE_SYS_INTR3 HDMI_CORE_SYS_REG(0x1CC) -#define HDMI_CORE_SYS_INTR4 HDMI_CORE_SYS_REG(0x1D0) -#define HDMI_CORE_SYS_UMASK1 HDMI_CORE_SYS_REG(0x1D4) -#define HDMI_CORE_SYS_TMDS_CTRL HDMI_CORE_SYS_REG(0x208) -#define HDMI_CORE_SYS_DE_DLY HDMI_CORE_SYS_REG(0xC8) -#define HDMI_CORE_SYS_DE_CTRL HDMI_CORE_SYS_REG(0xCC) -#define HDMI_CORE_SYS_DE_TOP HDMI_CORE_SYS_REG(0xD0) -#define HDMI_CORE_SYS_DE_CNTL HDMI_CORE_SYS_REG(0xD8) -#define HDMI_CORE_SYS_DE_CNTH HDMI_CORE_SYS_REG(0xDC) -#define HDMI_CORE_SYS_DE_LINL HDMI_CORE_SYS_REG(0xE0) -#define HDMI_CORE_SYS_DE_LINH_1 HDMI_CORE_SYS_REG(0xE4) + +#define HDMI_CORE_SYS_VND_IDL 0x0 +#define HDMI_CORE_SYS_DEV_IDL 0x8 +#define HDMI_CORE_SYS_DEV_IDH 0xC +#define HDMI_CORE_SYS_DEV_REV 0x10 +#define HDMI_CORE_SYS_SRST 0x14 +#define HDMI_CORE_CTRL1 0x20 +#define HDMI_CORE_SYS_SYS_STAT 0x24 +#define HDMI_CORE_SYS_VID_ACEN 0x124 +#define HDMI_CORE_SYS_VID_MODE 0x128 +#define HDMI_CORE_SYS_INTR_STATE 0x1C0 +#define HDMI_CORE_SYS_INTR1 0x1C4 +#define HDMI_CORE_SYS_INTR2 0x1C8 +#define HDMI_CORE_SYS_INTR3 0x1CC +#define HDMI_CORE_SYS_INTR4 0x1D0 +#define HDMI_CORE_SYS_UMASK1 0x1D4 +#define HDMI_CORE_SYS_TMDS_CTRL 0x208 +#define HDMI_CORE_SYS_DE_DLY 0xC8 +#define HDMI_CORE_SYS_DE_CTRL 0xCC +#define HDMI_CORE_SYS_DE_TOP 0xD0 +#define HDMI_CORE_SYS_DE_CNTL 0xD8 +#define HDMI_CORE_SYS_DE_CNTH 0xDC +#define HDMI_CORE_SYS_DE_LINL 0xE0 +#define HDMI_CORE_SYS_DE_LINH_1 0xE4 #define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC 0x1 #define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC 0x1 #define HDMI_CORE_CTRL1_BSEL_24BITBUS 0x1 #define HDMI_CORE_CTRL1_EDGE_RISINGEDGE 0x1 /* HDMI DDC E-DID */ -#define HDMI_CORE_DDC_CMD HDMI_CORE_SYS_REG(0x3CC) -#define HDMI_CORE_DDC_STATUS HDMI_CORE_SYS_REG(0x3C8) -#define HDMI_CORE_DDC_ADDR HDMI_CORE_SYS_REG(0x3B4) -#define HDMI_CORE_DDC_OFFSET HDMI_CORE_SYS_REG(0x3BC) -#define HDMI_CORE_DDC_COUNT1 HDMI_CORE_SYS_REG(0x3C0) -#define HDMI_CORE_DDC_COUNT2 HDMI_CORE_SYS_REG(0x3C4) -#define HDMI_CORE_DDC_DATA HDMI_CORE_SYS_REG(0x3D0) -#define HDMI_CORE_DDC_SEGM HDMI_CORE_SYS_REG(0x3B8) +#define HDMI_CORE_DDC_CMD 0x3CC +#define HDMI_CORE_DDC_STATUS 0x3C8 +#define HDMI_CORE_DDC_ADDR 0x3B4 +#define HDMI_CORE_DDC_OFFSET 0x3BC +#define HDMI_CORE_DDC_COUNT1 0x3C0 +#define HDMI_CORE_DDC_COUNT2 0x3C4 +#define HDMI_CORE_DDC_DATA 0x3D0 +#define HDMI_CORE_DDC_SEGM 0x3B8 /* HDMI IP Core Audio Video */ -#define HDMI_CORE_AV_REG(idx) HDMI_REG(HDMI_CORE_AV + idx) - -#define HDMI_CORE_AV_HDMI_CTRL HDMI_CORE_AV_REG(0xBC) -#define HDMI_CORE_AV_DPD HDMI_CORE_AV_REG(0xF4) -#define HDMI_CORE_AV_PB_CTRL1 HDMI_CORE_AV_REG(0xF8) -#define HDMI_CORE_AV_PB_CTRL2 HDMI_CORE_AV_REG(0xFC) -#define HDMI_CORE_AV_AVI_TYPE HDMI_CORE_AV_REG(0x100) -#define HDMI_CORE_AV_AVI_VERS HDMI_CORE_AV_REG(0x104) -#define HDMI_CORE_AV_AVI_LEN HDMI_CORE_AV_REG(0x108) -#define HDMI_CORE_AV_AVI_CHSUM HDMI_CORE_AV_REG(0x10C) -#define HDMI_CORE_AV_AVI_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x110) -#define HDMI_CORE_AV_AVI_DBYTE_NELEMS HDMI_CORE_AV_REG(15) -#define HDMI_CORE_AV_SPD_DBYTE HDMI_CORE_AV_REG(0x190) -#define HDMI_CORE_AV_SPD_DBYTE_NELEMS HDMI_CORE_AV_REG(27) -#define HDMI_CORE_AV_AUD_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x210) -#define HDMI_CORE_AV_AUD_DBYTE_NELEMS HDMI_CORE_AV_REG(10) -#define HDMI_CORE_AV_MPEG_DBYTE HDMI_CORE_AV_REG(0x290) -#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS HDMI_CORE_AV_REG(27) -#define HDMI_CORE_AV_GEN_DBYTE HDMI_CORE_AV_REG(0x300) -#define HDMI_CORE_AV_GEN_DBYTE_NELEMS HDMI_CORE_AV_REG(31) -#define HDMI_CORE_AV_GEN2_DBYTE HDMI_CORE_AV_REG(0x380) -#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS HDMI_CORE_AV_REG(31) -#define HDMI_CORE_AV_ACR_CTRL HDMI_CORE_AV_REG(0x4) -#define HDMI_CORE_AV_FREQ_SVAL HDMI_CORE_AV_REG(0x8) -#define HDMI_CORE_AV_N_SVAL1 HDMI_CORE_AV_REG(0xC) -#define HDMI_CORE_AV_N_SVAL2 HDMI_CORE_AV_REG(0x10) -#define HDMI_CORE_AV_N_SVAL3 HDMI_CORE_AV_REG(0x14) -#define HDMI_CORE_AV_CTS_SVAL1 HDMI_CORE_AV_REG(0x18) -#define HDMI_CORE_AV_CTS_SVAL2 HDMI_CORE_AV_REG(0x1C) -#define HDMI_CORE_AV_CTS_SVAL3 HDMI_CORE_AV_REG(0x20) -#define HDMI_CORE_AV_CTS_HVAL1 HDMI_CORE_AV_REG(0x24) -#define HDMI_CORE_AV_CTS_HVAL2 HDMI_CORE_AV_REG(0x28) -#define HDMI_CORE_AV_CTS_HVAL3 HDMI_CORE_AV_REG(0x2C) -#define HDMI_CORE_AV_AUD_MODE HDMI_CORE_AV_REG(0x50) -#define HDMI_CORE_AV_SPDIF_CTRL HDMI_CORE_AV_REG(0x54) -#define HDMI_CORE_AV_HW_SPDIF_FS HDMI_CORE_AV_REG(0x60) -#define HDMI_CORE_AV_SWAP_I2S HDMI_CORE_AV_REG(0x64) -#define HDMI_CORE_AV_SPDIF_ERTH HDMI_CORE_AV_REG(0x6C) -#define HDMI_CORE_AV_I2S_IN_MAP HDMI_CORE_AV_REG(0x70) -#define HDMI_CORE_AV_I2S_IN_CTRL HDMI_CORE_AV_REG(0x74) -#define HDMI_CORE_AV_I2S_CHST0 HDMI_CORE_AV_REG(0x78) -#define HDMI_CORE_AV_I2S_CHST1 HDMI_CORE_AV_REG(0x7C) -#define HDMI_CORE_AV_I2S_CHST2 HDMI_CORE_AV_REG(0x80) -#define HDMI_CORE_AV_I2S_CHST4 HDMI_CORE_AV_REG(0x84) -#define HDMI_CORE_AV_I2S_CHST5 HDMI_CORE_AV_REG(0x88) -#define HDMI_CORE_AV_ASRC HDMI_CORE_AV_REG(0x8C) -#define HDMI_CORE_AV_I2S_IN_LEN HDMI_CORE_AV_REG(0x90) -#define HDMI_CORE_AV_HDMI_CTRL HDMI_CORE_AV_REG(0xBC) -#define HDMI_CORE_AV_AUDO_TXSTAT HDMI_CORE_AV_REG(0xC0) -#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 HDMI_CORE_AV_REG(0xCC) -#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 HDMI_CORE_AV_REG(0xD0) -#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 HDMI_CORE_AV_REG(0xD4) -#define HDMI_CORE_AV_TEST_TXCTRL HDMI_CORE_AV_REG(0xF0) -#define HDMI_CORE_AV_DPD HDMI_CORE_AV_REG(0xF4) -#define HDMI_CORE_AV_PB_CTRL1 HDMI_CORE_AV_REG(0xF8) -#define HDMI_CORE_AV_PB_CTRL2 HDMI_CORE_AV_REG(0xFC) -#define HDMI_CORE_AV_AVI_TYPE HDMI_CORE_AV_REG(0x100) -#define HDMI_CORE_AV_AVI_VERS HDMI_CORE_AV_REG(0x104) -#define HDMI_CORE_AV_AVI_LEN HDMI_CORE_AV_REG(0x108) -#define HDMI_CORE_AV_AVI_CHSUM HDMI_CORE_AV_REG(0x10C) -#define HDMI_CORE_AV_SPD_TYPE HDMI_CORE_AV_REG(0x180) -#define HDMI_CORE_AV_SPD_VERS HDMI_CORE_AV_REG(0x184) -#define HDMI_CORE_AV_SPD_LEN HDMI_CORE_AV_REG(0x188) -#define HDMI_CORE_AV_SPD_CHSUM HDMI_CORE_AV_REG(0x18C) -#define HDMI_CORE_AV_AUDIO_TYPE HDMI_CORE_AV_REG(0x200) -#define HDMI_CORE_AV_AUDIO_VERS HDMI_CORE_AV_REG(0x204) -#define HDMI_CORE_AV_AUDIO_LEN HDMI_CORE_AV_REG(0x208) -#define HDMI_CORE_AV_AUDIO_CHSUM HDMI_CORE_AV_REG(0x20C) -#define HDMI_CORE_AV_MPEG_TYPE HDMI_CORE_AV_REG(0x280) -#define HDMI_CORE_AV_MPEG_VERS HDMI_CORE_AV_REG(0x284) -#define HDMI_CORE_AV_MPEG_LEN HDMI_CORE_AV_REG(0x288) -#define HDMI_CORE_AV_MPEG_CHSUM HDMI_CORE_AV_REG(0x28C) -#define HDMI_CORE_AV_CP_BYTE1 HDMI_CORE_AV_REG(0x37C) -#define HDMI_CORE_AV_CEC_ADDR_ID HDMI_CORE_AV_REG(0x3FC) + +#define HDMI_CORE_AV_HDMI_CTRL 0xBC +#define HDMI_CORE_AV_DPD 0xF4 +#define HDMI_CORE_AV_PB_CTRL1 0xF8 +#define HDMI_CORE_AV_PB_CTRL2 0xFC +#define HDMI_CORE_AV_AVI_TYPE 0x100 +#define HDMI_CORE_AV_AVI_VERS 0x104 +#define HDMI_CORE_AV_AVI_LEN 0x108 +#define HDMI_CORE_AV_AVI_CHSUM 0x10C +#define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110) +#define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15 +#define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190) +#define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27 +#define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210) +#define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10 +#define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290) +#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27 +#define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300) +#define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31 +#define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380) +#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31 +#define HDMI_CORE_AV_ACR_CTRL 0x4 +#define HDMI_CORE_AV_FREQ_SVAL 0x8 +#define HDMI_CORE_AV_N_SVAL1 0xC +#define HDMI_CORE_AV_N_SVAL2 0x10 +#define HDMI_CORE_AV_N_SVAL3 0x14 +#define HDMI_CORE_AV_CTS_SVAL1 0x18 +#define HDMI_CORE_AV_CTS_SVAL2 0x1C +#define HDMI_CORE_AV_CTS_SVAL3 0x20 +#define HDMI_CORE_AV_CTS_HVAL1 0x24 +#define HDMI_CORE_AV_CTS_HVAL2 0x28 +#define HDMI_CORE_AV_CTS_HVAL3 0x2C +#define HDMI_CORE_AV_AUD_MODE 0x50 +#define HDMI_CORE_AV_SPDIF_CTRL 0x54 +#define HDMI_CORE_AV_HW_SPDIF_FS 0x60 +#define HDMI_CORE_AV_SWAP_I2S 0x64 +#define HDMI_CORE_AV_SPDIF_ERTH 0x6C +#define HDMI_CORE_AV_I2S_IN_MAP 0x70 +#define HDMI_CORE_AV_I2S_IN_CTRL 0x74 +#define HDMI_CORE_AV_I2S_CHST0 0x78 +#define HDMI_CORE_AV_I2S_CHST1 0x7C +#define HDMI_CORE_AV_I2S_CHST2 0x80 +#define HDMI_CORE_AV_I2S_CHST4 0x84 +#define HDMI_CORE_AV_I2S_CHST5 0x88 +#define HDMI_CORE_AV_ASRC 0x8C +#define HDMI_CORE_AV_I2S_IN_LEN 0x90 +#define HDMI_CORE_AV_HDMI_CTRL 0xBC +#define HDMI_CORE_AV_AUDO_TXSTAT 0xC0 +#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 0xCC +#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 0xD0 +#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 0xD4 +#define HDMI_CORE_AV_TEST_TXCTRL 0xF0 +#define HDMI_CORE_AV_DPD 0xF4 +#define HDMI_CORE_AV_PB_CTRL1 0xF8 +#define HDMI_CORE_AV_PB_CTRL2 0xFC +#define HDMI_CORE_AV_AVI_TYPE 0x100 +#define HDMI_CORE_AV_AVI_VERS 0x104 +#define HDMI_CORE_AV_AVI_LEN 0x108 +#define HDMI_CORE_AV_AVI_CHSUM 0x10C +#define HDMI_CORE_AV_SPD_TYPE 0x180 +#define HDMI_CORE_AV_SPD_VERS 0x184 +#define HDMI_CORE_AV_SPD_LEN 0x188 +#define HDMI_CORE_AV_SPD_CHSUM 0x18C +#define HDMI_CORE_AV_AUDIO_TYPE 0x200 +#define HDMI_CORE_AV_AUDIO_VERS 0x204 +#define HDMI_CORE_AV_AUDIO_LEN 0x208 +#define HDMI_CORE_AV_AUDIO_CHSUM 0x20C +#define HDMI_CORE_AV_MPEG_TYPE 0x280 +#define HDMI_CORE_AV_MPEG_VERS 0x284 +#define HDMI_CORE_AV_MPEG_LEN 0x288 +#define HDMI_CORE_AV_MPEG_CHSUM 0x28C +#define HDMI_CORE_AV_CP_BYTE1 0x37C +#define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC #define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4 #define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4 #define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4 #define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4 /* PLL */ -#define HDMI_PLL_REG(idx) HDMI_REG(HDMI_PLLCTRL + idx) -#define PLLCTRL_PLL_CONTROL HDMI_PLL_REG(0x0) -#define PLLCTRL_PLL_STATUS HDMI_PLL_REG(0x4) -#define PLLCTRL_PLL_GO HDMI_PLL_REG(0x8) -#define PLLCTRL_CFG1 HDMI_PLL_REG(0xC) -#define PLLCTRL_CFG2 HDMI_PLL_REG(0x10) -#define PLLCTRL_CFG3 HDMI_PLL_REG(0x14) -#define PLLCTRL_CFG4 HDMI_PLL_REG(0x20) +#define PLLCTRL_PLL_CONTROL 0x0 +#define PLLCTRL_PLL_STATUS 0x4 +#define PLLCTRL_PLL_GO 0x8 +#define PLLCTRL_CFG1 0xC +#define PLLCTRL_CFG2 0x10 +#define PLLCTRL_CFG3 0x14 +#define PLLCTRL_CFG4 0x20 /* HDMI PHY */ -#define HDMI_PHY_REG(idx) HDMI_REG(HDMI_PHY + idx) - -#define HDMI_TXPHY_TX_CTRL HDMI_PHY_REG(0x0) -#define HDMI_TXPHY_DIGITAL_CTRL HDMI_PHY_REG(0x4) -#define HDMI_TXPHY_POWER_CTRL HDMI_PHY_REG(0x8) -#define HDMI_TXPHY_PAD_CFG_CTRL HDMI_PHY_REG(0xC) - -/* HDMI EDID Length */ -#define HDMI_EDID_MAX_LENGTH 256 -#define EDID_TIMING_DESCRIPTOR_SIZE 0x12 -#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36 -#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80 -#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 -#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 -#define OMAP_HDMI_TIMINGS_NB 34 +#define HDMI_TXPHY_TX_CTRL 0x0 +#define HDMI_TXPHY_DIGITAL_CTRL 0x4 +#define HDMI_TXPHY_POWER_CTRL 0x8 +#define HDMI_TXPHY_PAD_CFG_CTRL 0xC -#define REG_FLD_MOD(idx, val, start, end) \ - hdmi_write_reg(idx, FLD_MOD(hdmi_read_reg(idx), val, start, end)) -#define REG_GET(idx, start, end) \ - FLD_GET(hdmi_read_reg(idx), start, end) - -/* HDMI timing structure */ -struct hdmi_timings { - struct omap_video_timings timings; - int vsync_pol; - int hsync_pol; -}; +#define REG_FLD_MOD(base, idx, val, start, end) \ + hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\ + val, start, end)) +#define REG_GET(base, idx, start, end) \ + FLD_GET(hdmi_read_reg(base, idx), start, end) enum hdmi_phy_pwr { HDMI_PHYPWRCMD_OFF = 0, @@ -221,20 +196,6 @@ enum hdmi_phy_pwr { HDMI_PHYPWRCMD_TXON = 2 }; -enum hdmi_pll_pwr { - HDMI_PLLPWRCMD_ALLOFF = 0, - HDMI_PLLPWRCMD_PLLONLY = 1, - HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2, - HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3 -}; - -enum hdmi_clk_refsel { - HDMI_REFSEL_PCLK = 0, - HDMI_REFSEL_REF1 = 1, - HDMI_REFSEL_REF2 = 2, - HDMI_REFSEL_SYSCLK = 3 -}; - enum hdmi_core_inputbus_width { HDMI_INPUT_8BIT = 0, HDMI_INPUT_10BIT = 1, @@ -263,11 +224,6 @@ enum hdmi_core_packet_mode { HDMI_PACKETMODE48BITPERPIXEL = 7 }; -enum hdmi_core_hdmi_dvi { - HDMI_DVI = 0, - HDMI_HDMI = 1 -}; - enum hdmi_core_tclkselclkmult { HDMI_FPLL05IDCK = 0, HDMI_FPLL10IDCK = 1, @@ -495,40 +451,40 @@ struct hdmi_core_video_config { * details about infoframe databytes */ struct hdmi_core_infoframe_avi { + /* Y0, Y1 rgb,yCbCr */ u8 db1_format; - /* Y0, Y1 rgb,yCbCr */ + /* A0 Active information Present */ u8 db1_active_info; - /* A0 Active information Present */ + /* B0, B1 Bar info data valid */ u8 db1_bar_info_dv; - /* B0, B1 Bar info data valid */ + /* S0, S1 scan information */ u8 db1_scan_info; - /* S0, S1 scan information */ + /* C0, C1 colorimetry */ u8 db2_colorimetry; - /* C0, C1 colorimetry */ + /* M0, M1 Aspect ratio (4:3, 16:9) */ u8 db2_aspect_ratio; - /* M0, M1 Aspect ratio (4:3, 16:9) */ + /* R0...R3 Active format aspect ratio */ u8 db2_active_fmt_ar; - /* R0...R3 Active format aspect ratio */ + /* ITC IT content. */ u8 db3_itc; - /* ITC IT content. */ + /* EC0, EC1, EC2 Extended colorimetry */ u8 db3_ec; - /* EC0, EC1, EC2 Extended colorimetry */ + /* Q1, Q0 Quantization range */ u8 db3_q_range; - /* Q1, Q0 Quantization range */ + /* SC1, SC0 Non-uniform picture scaling */ u8 db3_nup_scaling; - /* SC1, SC0 Non-uniform picture scaling */ + /* VIC0..6 Video format identification */ u8 db4_videocode; - /* VIC0..6 Video format identification */ + /* PR0..PR3 Pixel repetition factor */ u8 db5_pixel_repeat; - /* PR0..PR3 Pixel repetition factor */ + /* Line number end of top bar */ u16 db6_7_line_eoftop; - /* Line number end of top bar */ + /* Line number start of bottom bar */ u16 db8_9_line_sofbottom; - /* Line number start of bottom bar */ + /* Pixel number end of left bar */ u16 db10_11_pixel_eofleft; - /* Pixel number end of left bar */ + /* Pixel number start of right bar */ u16 db12_13_pixel_sofright; - /* Pixel number start of right bar */ }; /* * Refer to section 8.2 in HDMI 1.3 specification for @@ -568,17 +524,6 @@ struct hdmi_video_interface { int tm; /* Timing mode */ }; -struct hdmi_cm { - int code; - int mode; -}; - -struct hdmi_config { - struct hdmi_timings timings; - u16 interlace; - struct hdmi_cm cm; -}; - struct hdmi_audio_format { enum hdmi_stereo_channels stereo_channels; u8 active_chnnls_msk; @@ -628,4 +573,21 @@ struct hdmi_core_audio_config { bool en_parallel_aud_input; bool en_spdif; }; + +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, + struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai); +int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, + u32 sample_freq, u32 *n, u32 *cts); +void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_infoframe_audio *info_aud); +void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, + struct hdmi_core_audio_config *cfg); +void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, + struct hdmi_audio_dma *aud_dma); +void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, + struct hdmi_audio_format *aud_fmt); +#endif #endif diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 173c664..7533458 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -295,7 +295,6 @@ static struct { u32 wss_data; struct regulator *vdda_dac_reg; - struct clk *tv_clk; struct clk *tv_dac_clk; } venc; @@ -464,9 +463,11 @@ static void venc_power_off(struct omap_dss_device *dssdev) regulator_disable(venc.vdda_dac_reg); } - - - +unsigned long venc_get_pixel_clock(void) +{ + /* VENC Pixel Clock in Mhz */ + return 13500000; +} /* driver */ static int venc_panel_probe(struct omap_dss_device *dssdev) @@ -732,22 +733,10 @@ static int venc_get_clocks(struct platform_device *pdev) { struct clk *clk; - clk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(clk)) { - DSSERR("can't get fck\n"); - return PTR_ERR(clk); - } - - venc.tv_clk = clk; - if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { - if (cpu_is_omap34xx() || cpu_is_omap3630()) - clk = clk_get(&pdev->dev, "dss_96m_fck"); - else - clk = clk_get(&pdev->dev, "tv_dac_clk"); + clk = clk_get(&pdev->dev, "tv_dac_clk"); if (IS_ERR(clk)) { DSSERR("can't get tv_dac_clk\n"); - clk_put(venc.tv_clk); return PTR_ERR(clk); } } else { @@ -761,8 +750,6 @@ static int venc_get_clocks(struct platform_device *pdev) static void venc_put_clocks(void) { - if (venc.tv_clk) - clk_put(venc.tv_clk); if (venc.tv_dac_clk) clk_put(venc.tv_dac_clk); } @@ -838,7 +825,6 @@ static int venc_runtime_suspend(struct device *dev) { if (venc.tv_dac_clk) clk_disable(venc.tv_dac_clk); - clk_disable(venc.tv_clk); dispc_runtime_put(); dss_runtime_put(); @@ -858,7 +844,6 @@ static int venc_runtime_resume(struct device *dev) if (r < 0) goto err_get_dispc; - clk_enable(venc.tv_clk); if (venc.tv_dac_clk) clk_enable(venc.tv_dac_clk); diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index aa33386..83d3fe7 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -1,5 +1,5 @@ menuconfig FB_OMAP2 - tristate "OMAP2+ frame buffer support (EXPERIMENTAL)" + tristate "OMAP2+ frame buffer support" depends on FB && OMAP2_DSS select OMAP2_VRAM diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 602b71a..70aa47d 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -808,19 +808,15 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, static void omapfb_calc_addr(const struct omapfb_info *ofbi, const struct fb_var_screeninfo *var, const struct fb_fix_screeninfo *fix, - int rotation, u32 *paddr, void __iomem **vaddr) + int rotation, u32 *paddr) { u32 data_start_p; - void __iomem *data_start_v; int offset; - if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); - data_start_v = NULL; - } else { + else data_start_p = omapfb_get_region_paddr(ofbi); - data_start_v = omapfb_get_region_vaddr(ofbi); - } if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) offset = calc_rotation_offset_vrfb(var, fix, rotation); @@ -828,16 +824,14 @@ static void omapfb_calc_addr(const struct omapfb_info *ofbi, offset = calc_rotation_offset_dma(var, fix, rotation); data_start_p += offset; - data_start_v += offset; if (offset) DBG("offset %d, %d = %d\n", var->xoffset, var->yoffset, offset); - DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); + DBG("paddr %x\n", data_start_p); *paddr = data_start_p; - *vaddr = data_start_v; } /* setup overlay according to the fb */ @@ -850,7 +844,6 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, struct fb_fix_screeninfo *fix = &fbi->fix; enum omap_color_mode mode = 0; u32 data_start_p = 0; - void __iomem *data_start_v = NULL; struct omap_overlay_info info; int xres, yres; int screen_width; @@ -880,8 +873,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, } if (ofbi->region->size) - omapfb_calc_addr(ofbi, var, fix, rotation, - &data_start_p, &data_start_v); + omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p); r = fb_mode_to_dss_mode(var, &mode); if (r) { @@ -910,7 +902,6 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, mirror = ofbi->mirror; info.paddr = data_start_p; - info.vaddr = data_start_v; info.screen_width = screen_width; info.width = xres; info.height = yres; @@ -2276,6 +2267,87 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) return r; } +static void fb_videomode_to_omap_timings(struct fb_videomode *m, + struct omap_video_timings *t) +{ + t->x_res = m->xres; + t->y_res = m->yres; + t->pixel_clock = PICOS2KHZ(m->pixclock); + t->hsw = m->hsync_len; + t->hfp = m->right_margin; + t->hbp = m->left_margin; + t->vsw = m->vsync_len; + t->vfp = m->lower_margin; + t->vbp = m->upper_margin; +} + +static int omapfb_find_best_mode(struct omap_dss_device *display, + struct omap_video_timings *timings) +{ + struct fb_monspecs *specs; + u8 *edid; + int r, i, best_xres, best_idx, len; + + if (!display->driver->read_edid) + return -ENODEV; + + len = 0x80 * 2; + edid = kmalloc(len, GFP_KERNEL); + + r = display->driver->read_edid(display, edid, len); + if (r < 0) + goto err1; + + specs = kzalloc(sizeof(*specs), GFP_KERNEL); + + fb_edid_to_monspecs(edid, specs); + + if (edid[126] > 0) + fb_edid_add_monspecs(edid + 0x80, specs); + + best_xres = 0; + best_idx = -1; + + for (i = 0; i < specs->modedb_len; ++i) { + struct fb_videomode *m; + struct omap_video_timings t; + + m = &specs->modedb[i]; + + if (m->pixclock == 0) + continue; + + /* skip repeated pixel modes */ + if (m->xres == 2880 || m->xres == 1440) + continue; + + fb_videomode_to_omap_timings(m, &t); + + r = display->driver->check_timings(display, &t); + if (r == 0 && best_xres < m->xres) { + best_xres = m->xres; + best_idx = i; + } + } + + if (best_xres == 0) { + r = -ENOENT; + goto err2; + } + + fb_videomode_to_omap_timings(&specs->modedb[best_idx], timings); + + r = 0; + +err2: + fb_destroy_modedb(specs->modedb); + kfree(specs); +err1: + kfree(edid); + + return r; +} + static int omapfb_init_display(struct omapfb2_device *fbdev, struct omap_dss_device *dssdev) { @@ -2373,8 +2445,10 @@ static int omapfb_probe(struct platform_device *pdev) omap_dss_get_device(dssdev); if (!dssdev->driver) { - dev_err(&pdev->dev, "no driver for display\n"); - r = -ENODEV; + dev_warn(&pdev->dev, "no driver for display: %s\n", + dssdev->name); + omap_dss_put_device(dssdev); + continue; } d = &fbdev->displays[fbdev->num_displays++]; @@ -2402,9 +2476,27 @@ static int omapfb_probe(struct platform_device *pdev) for (i = 0; i < fbdev->num_managers; i++) fbdev->managers[i] = omap_dss_get_overlay_manager(i); + /* gfx overlay should be the default one. find a display + * connected to that, and use it as default display */ + ovl = omap_dss_get_overlay(0); + if (ovl->manager && ovl->manager->device) { + def_display = ovl->manager->device; + } else { + dev_warn(&pdev->dev, "cannot find default display\n"); + def_display = NULL; + } + if (def_mode && strlen(def_mode) > 0) { if (omapfb_parse_def_modes(fbdev)) dev_warn(&pdev->dev, "cannot parse default modes\n"); + } else if (def_display && def_display->driver->set_timings && + def_display->driver->check_timings) { + struct omap_video_timings t; + + r = omapfb_find_best_mode(def_display, &t); + + if (r == 0) + def_display->driver->set_timings(def_display, &t); } r = omapfb_create_framebuffers(fbdev); @@ -2421,16 +2513,6 @@ static int omapfb_probe(struct platform_device *pdev) DBG("mgr->apply'ed\n"); - /* gfx overlay should be the default one. find a display - * connected to that, and use it as default display */ - ovl = omap_dss_get_overlay(0); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; - } else { - dev_warn(&pdev->dev, "cannot find default display\n"); - def_display = NULL; - } - if (def_display) { r = omapfb_init_display(fbdev, def_display); if (r) { diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 153bf1a..1694d51 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -104,16 +104,14 @@ static ssize_t store_mirror(struct device *dev, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - int mirror; + bool mirror; int r; struct fb_var_screeninfo new_var; - r = kstrtoint(buf, 0, &mirror); + r = strtobool(buf, &mirror); if (r) return r; - mirror = !!mirror; - if (!lock_fb_info(fbi)) return -ENODEV; |