mirror of https://gitee.com/openkylin/linux.git
omapdrm changes for v4.6
* HDMI interlace output support * DMAbuf import support * Big refactoring leading to removal of legacy code * Various non-critical fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJW2Y2tAAoJEPo9qoy8lh71MPoP/ikqFMmkmtXgn3ND/IRXfkbz UUDgdOf7TyzMgTVJEKv8MMz/Da2P9AxTtv4unImZoy9OswfYuNETOViMw3Yj26aM SNKWxHCA3yDUHndvwLUC8tMhpDXAXC1AdrIbuvj/H/5+Hox89Xo7L3CVMtdE68vN 9mlpxUJDqudMiUCv15Pi7YfLYJmzWLHGx7g+a6f6+KCPbtSWF7777MsSlxwPr1uP M44cjseq8debLn8wWHl4Vzm40Wr4t0vzEo8oRIdBTs15YMQnPGanuIxvW/byPaCN dXnEo98cD0wjd6lutMwEW0LQBCueQlsLgFRPHuUdhT0Z1NsiV7V892MH+QmePbzK +MeV0TA3+34fj9ngSc8dqx7re26z8YNAkGrEZHYQTepjrzk4baS9GVZL9c4c5oV/ PSzoeC8ipPNMtbLJtgqIijvlO9Ir61J4twaGqhmJXiktsX+KZa0RuJ/RubT1ABmJ Fkv9Jo4GK6ZxyH3xI6kJFxbf835/vaPRxCdd40Tp2H79w+1bxy37ieqhybLcQjqn hR0Apn/VP0qREdw5naP1el+79R56vNogwsH7m/h3hM2DCMiwB7QuOTtoWw7eSDOW ruOvLoNryYgQgMTK5baaTfeDo8lmYzjJch71W0zhlBa6qBXKl1dsVKWK7yKtbiXx MabEhh52njL4pYF32wjW =+fwk -----END PGP SIGNATURE----- Merge tag 'omapdrm-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next omapdrm changes for v4.6 * HDMI interlace output support * DMAbuf import support * Big refactoring leading to removal of legacy code * Various non-critical fixes * tag 'omapdrm-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (76 commits) drm/omap: no need to select OMAP2_DSS drm/omap: gem: Fix omap_gem_new() error path drm/omap: remove -Werror from Makefile drm/omap: remove dispc_ovl_check() drm/omap: remove dss compat code drm/omap: remove last uses of omap_overlay_manager drm/omap: DSI: remove uses of omap_overlay_manager drm/omap: VENC: remove uses of omap_overlay_manager drm/omap: SDI: remove uses of omap_overlay_manager drm/omap: HDMI4: remove uses of omap_overlay_manager drm/omap: HDMI5: remove uses of omap_overlay_manager drm/omap: DPI: remove uses of omap_overlay_manager drm/omap: remove extra manager checks on disconnect drm/omap: remove extra check in dpi and sdi drm/omap: convert dss_mgr_unregister_framedone_handler to accept omap_channel drm/omap: convert dss_mgr_register_framedone_handler to accept omap_channel drm/omap: convert dss_mgr_start_update to accept omap_channel drm/omap: convert dss_mgr_disable to accept omap_channel drm/omap: convert dss_mgr_enable to accept omap_channel drm/omap: convert dss_mgr_set_lcd_config to accept omap_channel ...
This commit is contained in:
commit
a90cc3f250
|
@ -2,7 +2,6 @@ config DRM_OMAP
|
|||
tristate "OMAP DRM"
|
||||
depends on DRM
|
||||
depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
|
||||
select OMAP2_DSS
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_KMS_FB_HELPER
|
||||
select FB_SYS_FILLRECT
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
obj-y += dss/
|
||||
obj-y += displays/
|
||||
|
||||
ccflags-y := -Iinclude/drm -Werror
|
||||
ccflags-y := -Iinclude/drm
|
||||
omapdrm-y := omap_drv.o \
|
||||
omap_irq.o \
|
||||
omap_debugfs.o \
|
||||
|
|
|
@ -236,46 +236,6 @@ static struct omap_dss_driver dvic_driver = {
|
|||
.detect = dvic_detect,
|
||||
};
|
||||
|
||||
static int dvic_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct connector_dvi_platform_data *pdata;
|
||||
struct omap_dss_device *in, *dssdev;
|
||||
int i2c_bus_num;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
i2c_bus_num = pdata->i2c_bus_num;
|
||||
|
||||
if (i2c_bus_num != -1) {
|
||||
struct i2c_adapter *adapter;
|
||||
|
||||
adapter = i2c_get_adapter(i2c_bus_num);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get I2C adapter, bus %d\n",
|
||||
i2c_bus_num);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->i2c_adapter = adapter;
|
||||
}
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvic_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
|
@ -319,17 +279,12 @@ static int dvic_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = dvic_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (pdev->dev.of_node) {
|
||||
r = dvic_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = dvic_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ddata->timings = dvic_default_timings;
|
||||
|
||||
|
|
|
@ -206,30 +206,6 @@ static struct omap_dss_driver hdmic_driver = {
|
|||
.set_hdmi_infoframe = hdmic_set_infoframe,
|
||||
};
|
||||
|
||||
static int hdmic_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct connector_hdmi_platform_data *pdata;
|
||||
struct omap_dss_device *in, *dssdev;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
ddata->hpd_gpio = -ENODEV;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmic_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
|
@ -268,17 +244,12 @@ static int hdmic_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, ddata);
|
||||
ddata->dev = &pdev->dev;
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = hdmic_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (pdev->dev.of_node) {
|
||||
r = hdmic_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = hdmic_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->hpd_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
|
||||
|
|
|
@ -166,32 +166,6 @@ static const struct omapdss_dvi_ops tfp410_dvi_ops = {
|
|||
.get_timings = tfp410_get_timings,
|
||||
};
|
||||
|
||||
static int tfp410_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct encoder_tfp410_platform_data *pdata;
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
ddata->pd_gpio = pdata->power_down_gpio;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tfp410_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
|
@ -231,17 +205,12 @@ static int tfp410_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = tfp410_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (pdev->dev.of_node) {
|
||||
r = tfp410_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = tfp410_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->pd_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->pd_gpio,
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
@ -24,9 +23,9 @@ struct panel_drv_data {
|
|||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
int ct_cp_hpd_gpio;
|
||||
int ls_oe_gpio;
|
||||
int hpd_gpio;
|
||||
struct gpio_desc *ct_cp_hpd_gpio;
|
||||
struct gpio_desc *ls_oe_gpio;
|
||||
struct gpio_desc *hpd_gpio;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
};
|
||||
|
@ -47,7 +46,7 @@ static int tpd_connect(struct omap_dss_device *dssdev,
|
|||
dst->src = dssdev;
|
||||
dssdev->dst = dst;
|
||||
|
||||
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
|
||||
gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
|
||||
/* DC-DC converter needs at max 300us to get to 90% of 5V */
|
||||
udelay(300);
|
||||
|
||||
|
@ -65,7 +64,7 @@ static void tpd_disconnect(struct omap_dss_device *dssdev,
|
|||
if (dst != dssdev->dst)
|
||||
return;
|
||||
|
||||
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
|
||||
gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
|
||||
|
||||
dst->src = NULL;
|
||||
dssdev->dst = NULL;
|
||||
|
@ -145,16 +144,14 @@ static int tpd_read_edid(struct omap_dss_device *dssdev,
|
|||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!gpio_get_value_cansleep(ddata->hpd_gpio))
|
||||
if (!gpiod_get_value_cansleep(ddata->hpd_gpio))
|
||||
return -ENODEV;
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio))
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
|
||||
gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
|
||||
|
||||
r = in->ops.hdmi->read_edid(in, edid, len);
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio))
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
|
||||
gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -163,7 +160,7 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
|
|||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
return gpio_get_value_cansleep(ddata->hpd_gpio);
|
||||
return gpiod_get_value_cansleep(ddata->hpd_gpio);
|
||||
}
|
||||
|
||||
static int tpd_set_infoframe(struct omap_dss_device *dssdev,
|
||||
|
@ -201,63 +198,11 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
|
|||
.set_hdmi_mode = tpd_set_hdmi_mode,
|
||||
};
|
||||
|
||||
static int tpd_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct encoder_tpd12s015_platform_data *pdata;
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
ddata->ct_cp_hpd_gpio = pdata->ct_cp_hpd_gpio;
|
||||
ddata->ls_oe_gpio = pdata->ls_oe_gpio;
|
||||
ddata->hpd_gpio = pdata->hpd_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpd_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct omap_dss_device *in;
|
||||
int gpio;
|
||||
|
||||
/* CT CP HPD GPIO */
|
||||
gpio = of_get_gpio(node, 0);
|
||||
if (!gpio_is_valid(gpio)) {
|
||||
dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n");
|
||||
return gpio;
|
||||
}
|
||||
ddata->ct_cp_hpd_gpio = gpio;
|
||||
|
||||
/* LS OE GPIO */
|
||||
gpio = of_get_gpio(node, 1);
|
||||
if (gpio_is_valid(gpio) || gpio == -ENOENT) {
|
||||
ddata->ls_oe_gpio = gpio;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "failed to parse LS OE gpio\n");
|
||||
return gpio;
|
||||
}
|
||||
|
||||
/* HPD GPIO */
|
||||
gpio = of_get_gpio(node, 2);
|
||||
if (!gpio_is_valid(gpio)) {
|
||||
dev_err(&pdev->dev, "failed to parse HPD gpio\n");
|
||||
return gpio;
|
||||
}
|
||||
ddata->hpd_gpio = gpio;
|
||||
|
||||
in = omapdss_of_find_source_for_first_ep(node);
|
||||
if (IS_ERR(in)) {
|
||||
|
@ -275,6 +220,7 @@ static int tpd_probe(struct platform_device *pdev)
|
|||
struct omap_dss_device *in, *dssdev;
|
||||
struct panel_drv_data *ddata;
|
||||
int r;
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
|
@ -282,35 +228,35 @@ static int tpd_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = tpd_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (pdev->dev.of_node) {
|
||||
r = tpd_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd");
|
||||
r = tpd_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
||||
gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
goto err_gpio;
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio)) {
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->ls_oe_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "hdmi_ls_oe");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
}
|
||||
ddata->ct_cp_hpd_gpio = gpio;
|
||||
|
||||
r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
|
||||
GPIOF_DIR_IN, "hdmi_hpd");
|
||||
if (r)
|
||||
gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
goto err_gpio;
|
||||
|
||||
ddata->ls_oe_gpio = gpio;
|
||||
|
||||
gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2,
|
||||
GPIOD_IN);
|
||||
if (IS_ERR(gpio))
|
||||
goto err_gpio;
|
||||
|
||||
ddata->hpd_gpio = gpio;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops.hdmi = &tpd_hdmi_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
|
|
|
@ -1127,40 +1127,6 @@ static struct omap_dss_driver dsicm_ops = {
|
|||
.memory_read = dsicm_memory_read,
|
||||
};
|
||||
|
||||
static int dsicm_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
const struct panel_dsicm_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "failed to find video source\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
ddata->in = in;
|
||||
|
||||
ddata->reset_gpio = pdata->reset_gpio;
|
||||
|
||||
if (pdata->use_ext_te)
|
||||
ddata->ext_te_gpio = pdata->ext_te_gpio;
|
||||
else
|
||||
ddata->ext_te_gpio = -1;
|
||||
|
||||
ddata->ulps_timeout = pdata->ulps_timeout;
|
||||
|
||||
ddata->use_dsi_backlight = pdata->use_dsi_backlight;
|
||||
|
||||
ddata->pin_config = pdata->pin_config;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsicm_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
@ -1214,17 +1180,12 @@ static int dsicm_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, ddata);
|
||||
ddata->pdev = pdev;
|
||||
|
||||
if (dev_get_platdata(dev)) {
|
||||
r = dsicm_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (pdev->dev.of_node) {
|
||||
r = dsicm_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = dsicm_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ddata->timings.x_res = 864;
|
||||
ddata->timings.y_res = 480;
|
||||
|
|
|
@ -240,44 +240,6 @@ static struct omap_dss_driver lb035q02_ops = {
|
|||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
static int lb035q02_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_lb035q02_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
int r;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "panel enable");
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
|
||||
ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
|
||||
|
||||
ddata->backlight_gpio = pdata->backlight_gpio;
|
||||
|
||||
return 0;
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int lb035q02_probe_of(struct spi_device *spi)
|
||||
{
|
||||
struct device_node *node = spi->dev.of_node;
|
||||
|
@ -320,17 +282,12 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi)
|
|||
|
||||
ddata->spi = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = lb035q02_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (spi->dev.of_node) {
|
||||
r = lb035q02_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!spi->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = lb035q02_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->backlight_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio,
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
|
@ -232,34 +231,6 @@ static struct omap_dss_driver nec_8048_ops = {
|
|||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
|
||||
static int nec_8048_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_nec_nl8048hl11_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
ddata->qvga_gpio = pdata->qvga_gpio;
|
||||
ddata->res_gpio = pdata->res_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nec_8048_probe_of(struct spi_device *spi)
|
||||
{
|
||||
struct device_node *node = spi->dev.of_node;
|
||||
|
@ -315,17 +286,12 @@ static int nec_8048_probe(struct spi_device *spi)
|
|||
|
||||
ddata->spi = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = nec_8048_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (spi->dev.of_node) {
|
||||
r = nec_8048_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!spi->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = nec_8048_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (gpio_is_valid(ddata->qvga_gpio)) {
|
||||
r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
|
@ -197,73 +196,6 @@ static struct omap_dss_driver sharp_ls_ops = {
|
|||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
static int sharp_ls_get_gpio(struct device *dev, int gpio, unsigned long flags,
|
||||
char *desc, struct gpio_desc **gpiod)
|
||||
{
|
||||
struct gpio_desc *gd;
|
||||
int r;
|
||||
|
||||
*gpiod = NULL;
|
||||
|
||||
r = devm_gpio_request_one(dev, gpio, flags, desc);
|
||||
if (r)
|
||||
return r == -ENOENT ? 0 : r;
|
||||
|
||||
gd = gpio_to_desc(gpio);
|
||||
if (IS_ERR(gd))
|
||||
return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd);
|
||||
|
||||
*gpiod = gd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_ls_probe_pdata(struct platform_device *pdev)
|
||||
{
|
||||
const struct panel_sharp_ls037v7dw01_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
int r;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&pdev->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
r = sharp_ls_get_gpio(&pdev->dev, pdata->mo_gpio, GPIOF_OUT_INIT_LOW,
|
||||
"lcd MO", &ddata->mo_gpio);
|
||||
if (r)
|
||||
return r;
|
||||
r = sharp_ls_get_gpio(&pdev->dev, pdata->lr_gpio, GPIOF_OUT_INIT_HIGH,
|
||||
"lcd LR", &ddata->lr_gpio);
|
||||
if (r)
|
||||
return r;
|
||||
r = sharp_ls_get_gpio(&pdev->dev, pdata->ud_gpio, GPIOF_OUT_INIT_HIGH,
|
||||
"lcd UD", &ddata->ud_gpio);
|
||||
if (r)
|
||||
return r;
|
||||
r = sharp_ls_get_gpio(&pdev->dev, pdata->resb_gpio, GPIOF_OUT_INIT_LOW,
|
||||
"lcd RESB", &ddata->resb_gpio);
|
||||
if (r)
|
||||
return r;
|
||||
r = sharp_ls_get_gpio(&pdev->dev, pdata->ini_gpio, GPIOF_OUT_INIT_LOW,
|
||||
"lcd INI", &ddata->ini_gpio);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
|
||||
const char *desc, struct gpio_desc **gpiod)
|
||||
{
|
||||
|
@ -340,17 +272,12 @@ static int sharp_ls_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = sharp_ls_probe_pdata(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (pdev->dev.of_node) {
|
||||
r = sharp_ls_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = sharp_ls_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ddata->videomode = sharp_ls_timings;
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
|
@ -365,31 +364,6 @@ static struct omap_dss_driver td028ttec1_ops = {
|
|||
.check_timings = td028ttec1_panel_check_timings,
|
||||
};
|
||||
|
||||
static int td028ttec1_panel_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_tpo_td028ttec1_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int td028ttec1_probe_of(struct spi_device *spi)
|
||||
{
|
||||
struct device_node *node = spi->dev.of_node;
|
||||
|
@ -432,17 +406,12 @@ static int td028ttec1_panel_probe(struct spi_device *spi)
|
|||
|
||||
ddata->spi_dev = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = td028ttec1_panel_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (spi->dev.of_node) {
|
||||
r = td028ttec1_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!spi->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = td028ttec1_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ddata->videomode = td028ttec1_panel_timings;
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#define TPO_R02_MODE(x) ((x) & 7)
|
||||
#define TPO_R02_MODE_800x480 7
|
||||
|
@ -464,33 +463,6 @@ static struct omap_dss_driver tpo_td043_ops = {
|
|||
.get_resolution = omapdss_default_get_resolution,
|
||||
};
|
||||
|
||||
|
||||
static int tpo_td043_probe_pdata(struct spi_device *spi)
|
||||
{
|
||||
const struct panel_tpo_td043mtea1_platform_data *pdata;
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
|
||||
pdata = dev_get_platdata(&spi->dev);
|
||||
|
||||
ddata->nreset_gpio = pdata->nreset_gpio;
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
dev_err(&spi->dev, "failed to find video source '%s'\n",
|
||||
pdata->source);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
ddata->in = in;
|
||||
|
||||
ddata->data_lines = pdata->data_lines;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpo_td043_probe_of(struct spi_device *spi)
|
||||
{
|
||||
struct device_node *node = spi->dev.of_node;
|
||||
|
@ -541,17 +513,12 @@ static int tpo_td043_probe(struct spi_device *spi)
|
|||
|
||||
ddata->spi = spi;
|
||||
|
||||
if (dev_get_platdata(&spi->dev)) {
|
||||
r = tpo_td043_probe_pdata(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else if (spi->dev.of_node) {
|
||||
r = tpo_td043_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
if (!spi->dev.of_node)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = tpo_td043_probe_of(spi);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ddata->mode = TPO_R02_MODE_800x480;
|
||||
memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma));
|
||||
|
|
|
@ -3,9 +3,6 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o
|
|||
# Core DSS files
|
||||
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
|
||||
output.o dss-of.o pll.o video-pll.o
|
||||
# DSS compat layer files
|
||||
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
|
||||
dispc-compat.o display-sysfs.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -165,32 +165,20 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
|
|||
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
|
||||
|
||||
/* PLATFORM DEVICE */
|
||||
static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
|
||||
|
||||
static void dss_disable_all_devices(void)
|
||||
{
|
||||
DSSDBG("pm notif %lu\n", v);
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
switch (v) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
case PM_RESTORE_PREPARE:
|
||||
DSSDBG("suspending displays\n");
|
||||
return dss_suspend_all_devices();
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
case PM_POST_HIBERNATION:
|
||||
case PM_POST_RESTORE:
|
||||
DSSDBG("resuming displays\n");
|
||||
return dss_resume_all_devices();
|
||||
|
||||
default:
|
||||
return 0;
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
dssdev->driver->disable(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
static struct notifier_block omap_dss_pm_notif_block = {
|
||||
.notifier_call = omap_dss_pm_notif,
|
||||
};
|
||||
|
||||
static int __init omap_dss_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
||||
|
@ -211,8 +199,6 @@ static int __init omap_dss_probe(struct platform_device *pdev)
|
|||
else if (pdata->default_device)
|
||||
core.default_display_name = pdata->default_device->name;
|
||||
|
||||
register_pm_notifier(&omap_dss_pm_notif_block);
|
||||
|
||||
return 0;
|
||||
|
||||
err_debugfs:
|
||||
|
@ -222,8 +208,6 @@ static int __init omap_dss_probe(struct platform_device *pdev)
|
|||
|
||||
static int omap_dss_remove(struct platform_device *pdev)
|
||||
{
|
||||
unregister_pm_notifier(&omap_dss_pm_notif_block);
|
||||
|
||||
dss_uninitialize_debugfs();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,667 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Texas Instruments
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "APPLY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
#include "dispc-compat.h"
|
||||
|
||||
#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
|
||||
DISPC_IRQ_OCP_ERR | \
|
||||
DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
|
||||
DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
|
||||
DISPC_IRQ_SYNC_LOST | \
|
||||
DISPC_IRQ_SYNC_LOST_DIGIT)
|
||||
|
||||
#define DISPC_MAX_NR_ISRS 8
|
||||
|
||||
struct omap_dispc_isr_data {
|
||||
omap_dispc_isr_t isr;
|
||||
void *arg;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
struct dispc_irq_stats {
|
||||
unsigned long last_reset;
|
||||
unsigned irq_count;
|
||||
unsigned irqs[32];
|
||||
};
|
||||
|
||||
static struct {
|
||||
spinlock_t irq_lock;
|
||||
u32 irq_error_mask;
|
||||
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
|
||||
u32 error_irqs;
|
||||
struct work_struct error_work;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
spinlock_t irq_stats_lock;
|
||||
struct dispc_irq_stats irq_stats;
|
||||
#endif
|
||||
} dispc_compat;
|
||||
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
static void dispc_dump_irqs(struct seq_file *s)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dispc_irq_stats stats;
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
|
||||
|
||||
stats = dispc_compat.irq_stats;
|
||||
memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
|
||||
dispc_compat.irq_stats.last_reset = jiffies;
|
||||
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
|
||||
|
||||
seq_printf(s, "period %u ms\n",
|
||||
jiffies_to_msecs(jiffies - stats.last_reset));
|
||||
|
||||
seq_printf(s, "irqs %d\n", stats.irq_count);
|
||||
#define PIS(x) \
|
||||
seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
|
||||
|
||||
PIS(FRAMEDONE);
|
||||
PIS(VSYNC);
|
||||
PIS(EVSYNC_EVEN);
|
||||
PIS(EVSYNC_ODD);
|
||||
PIS(ACBIAS_COUNT_STAT);
|
||||
PIS(PROG_LINE_NUM);
|
||||
PIS(GFX_FIFO_UNDERFLOW);
|
||||
PIS(GFX_END_WIN);
|
||||
PIS(PAL_GAMMA_MASK);
|
||||
PIS(OCP_ERR);
|
||||
PIS(VID1_FIFO_UNDERFLOW);
|
||||
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);
|
||||
if (dss_has_feature(FEAT_MGR_LCD2)) {
|
||||
PIS(FRAMEDONE2);
|
||||
PIS(VSYNC2);
|
||||
PIS(ACBIAS_COUNT_STAT2);
|
||||
PIS(SYNC_LOST2);
|
||||
}
|
||||
if (dss_has_feature(FEAT_MGR_LCD3)) {
|
||||
PIS(FRAMEDONE3);
|
||||
PIS(VSYNC3);
|
||||
PIS(ACBIAS_COUNT_STAT3);
|
||||
PIS(SYNC_LOST3);
|
||||
}
|
||||
#undef PIS
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dispc.irq_lock has to be locked by the caller */
|
||||
static void _omap_dispc_set_irqs(void)
|
||||
{
|
||||
u32 mask;
|
||||
int i;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
|
||||
mask = dispc_compat.irq_error_mask;
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
|
||||
if (isr_data->isr == NULL)
|
||||
continue;
|
||||
|
||||
mask |= isr_data->mask;
|
||||
}
|
||||
|
||||
dispc_write_irqenable(mask);
|
||||
}
|
||||
|
||||
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
|
||||
if (isr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
|
||||
/* check for duplicate entry */
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
if (isr_data->isr == isr && isr_data->arg == arg &&
|
||||
isr_data->mask == mask) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
isr_data = NULL;
|
||||
ret = -EBUSY;
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
|
||||
if (isr_data->isr != NULL)
|
||||
continue;
|
||||
|
||||
isr_data->isr = isr;
|
||||
isr_data->arg = arg;
|
||||
isr_data->mask = mask;
|
||||
ret = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dispc_register_isr);
|
||||
|
||||
int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = &dispc_compat.registered_isr[i];
|
||||
if (isr_data->isr != isr || isr_data->arg != arg ||
|
||||
isr_data->mask != mask)
|
||||
continue;
|
||||
|
||||
/* found the correct isr */
|
||||
|
||||
isr_data->isr = NULL;
|
||||
isr_data->arg = NULL;
|
||||
isr_data->mask = 0;
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dispc_unregister_isr);
|
||||
|
||||
static void print_irq_status(u32 status)
|
||||
{
|
||||
if ((status & dispc_compat.irq_error_mask) == 0)
|
||||
return;
|
||||
|
||||
#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
|
||||
|
||||
pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
|
||||
status,
|
||||
PIS(OCP_ERR),
|
||||
PIS(GFX_FIFO_UNDERFLOW),
|
||||
PIS(VID1_FIFO_UNDERFLOW),
|
||||
PIS(VID2_FIFO_UNDERFLOW),
|
||||
dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
|
||||
PIS(SYNC_LOST),
|
||||
PIS(SYNC_LOST_DIGIT),
|
||||
dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
|
||||
dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
|
||||
#undef PIS
|
||||
}
|
||||
|
||||
/* Called from dss.c. Note that we don't touch clocks here,
|
||||
* but we presume they are on because we got an IRQ. However,
|
||||
* an irq handler may turn the clocks off, so we may not have
|
||||
* clock later in the function. */
|
||||
static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
|
||||
{
|
||||
int i;
|
||||
u32 irqstatus, irqenable;
|
||||
u32 handledirqs = 0;
|
||||
u32 unhandled_errors;
|
||||
struct omap_dispc_isr_data *isr_data;
|
||||
struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
|
||||
|
||||
spin_lock(&dispc_compat.irq_lock);
|
||||
|
||||
irqstatus = dispc_read_irqstatus();
|
||||
irqenable = dispc_read_irqenable();
|
||||
|
||||
/* IRQ is not for us */
|
||||
if (!(irqstatus & irqenable)) {
|
||||
spin_unlock(&dispc_compat.irq_lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
spin_lock(&dispc_compat.irq_stats_lock);
|
||||
dispc_compat.irq_stats.irq_count++;
|
||||
dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
|
||||
spin_unlock(&dispc_compat.irq_stats_lock);
|
||||
#endif
|
||||
|
||||
print_irq_status(irqstatus);
|
||||
|
||||
/* Ack the interrupt. Do it here before clocks are possibly turned
|
||||
* off */
|
||||
dispc_clear_irqstatus(irqstatus);
|
||||
/* flush posted write */
|
||||
dispc_read_irqstatus();
|
||||
|
||||
/* make a copy and unlock, so that isrs can unregister
|
||||
* themselves */
|
||||
memcpy(registered_isr, dispc_compat.registered_isr,
|
||||
sizeof(registered_isr));
|
||||
|
||||
spin_unlock(&dispc_compat.irq_lock);
|
||||
|
||||
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
|
||||
isr_data = ®istered_isr[i];
|
||||
|
||||
if (!isr_data->isr)
|
||||
continue;
|
||||
|
||||
if (isr_data->mask & irqstatus) {
|
||||
isr_data->isr(isr_data->arg, irqstatus);
|
||||
handledirqs |= isr_data->mask;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&dispc_compat.irq_lock);
|
||||
|
||||
unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
|
||||
|
||||
if (unhandled_errors) {
|
||||
dispc_compat.error_irqs |= unhandled_errors;
|
||||
|
||||
dispc_compat.irq_error_mask &= ~unhandled_errors;
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
schedule_work(&dispc_compat.error_work);
|
||||
}
|
||||
|
||||
spin_unlock(&dispc_compat.irq_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
errors = dispc_compat.error_irqs;
|
||||
dispc_compat.error_irqs = 0;
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
dispc_runtime_get();
|
||||
|
||||
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
|
||||
struct omap_overlay *ovl;
|
||||
unsigned bit;
|
||||
|
||||
ovl = omap_dss_get_overlay(i);
|
||||
bit = fifo_underflow_bits[i];
|
||||
|
||||
if (bit & errors) {
|
||||
DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
|
||||
ovl->name);
|
||||
ovl->disable(ovl);
|
||||
msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
struct omap_overlay_manager *mgr;
|
||||
unsigned bit;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
bit = dispc_mgr_get_sync_lost_irq(i);
|
||||
|
||||
if (bit & errors) {
|
||||
int j;
|
||||
|
||||
DSSERR("SYNC_LOST on channel %s, restarting the output "
|
||||
"with video overlays disabled\n",
|
||||
mgr->name);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
|
||||
struct omap_overlay *ovl;
|
||||
ovl = omap_dss_get_overlay(j);
|
||||
|
||||
if (ovl->id != OMAP_DSS_GFX &&
|
||||
ovl->manager == mgr)
|
||||
ovl->disable(ovl);
|
||||
}
|
||||
|
||||
dss_mgr_enable(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors & DISPC_IRQ_OCP_ERR) {
|
||||
DSSERR("OCP_ERR\n");
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
dss_mgr_disable(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dispc_compat.irq_lock, flags);
|
||||
dispc_compat.irq_error_mask |= errors;
|
||||
_omap_dispc_set_irqs();
|
||||
spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
|
||||
|
||||
dispc_runtime_put();
|
||||
}
|
||||
|
||||
int dss_dispc_initialize_irq(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
|
||||
spin_lock_init(&dispc_compat.irq_stats_lock);
|
||||
dispc_compat.irq_stats.last_reset = jiffies;
|
||||
dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
|
||||
#endif
|
||||
|
||||
spin_lock_init(&dispc_compat.irq_lock);
|
||||
|
||||
memset(dispc_compat.registered_isr, 0,
|
||||
sizeof(dispc_compat.registered_isr));
|
||||
|
||||
dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
|
||||
if (dss_has_feature(FEAT_MGR_LCD2))
|
||||
dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
|
||||
if (dss_has_feature(FEAT_MGR_LCD3))
|
||||
dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
|
||||
if (dss_feat_get_num_ovls() > 3)
|
||||
dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
|
||||
|
||||
/*
|
||||
* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
|
||||
* so clear it
|
||||
*/
|
||||
dispc_clear_irqstatus(dispc_read_irqstatus());
|
||||
|
||||
INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
|
||||
|
||||
_omap_dispc_set_irqs();
|
||||
|
||||
r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
|
||||
if (r) {
|
||||
DSSERR("dispc_request_irq failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_dispc_uninitialize_irq(void)
|
||||
{
|
||||
dispc_free_irq(&dispc_compat);
|
||||
}
|
||||
|
||||
static void dispc_mgr_disable_isr(void *data, u32 mask)
|
||||
{
|
||||
struct completion *compl = data;
|
||||
complete(compl);
|
||||
}
|
||||
|
||||
static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
|
||||
{
|
||||
dispc_mgr_enable(channel, true);
|
||||
}
|
||||
|
||||
static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(framedone_compl);
|
||||
int r;
|
||||
u32 irq;
|
||||
|
||||
if (!dispc_mgr_is_enabled(channel))
|
||||
return;
|
||||
|
||||
/*
|
||||
* When we disable LCD output, we need to wait for FRAMEDONE to know
|
||||
* that DISPC has finished with the LCD output.
|
||||
*/
|
||||
|
||||
irq = dispc_mgr_get_framedone_irq(channel);
|
||||
|
||||
r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq);
|
||||
if (r)
|
||||
DSSERR("failed to register FRAMEDONE isr\n");
|
||||
|
||||
dispc_mgr_enable(channel, false);
|
||||
|
||||
/* if we couldn't register for framedone, just sleep and exit */
|
||||
if (r) {
|
||||
msleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&framedone_compl,
|
||||
msecs_to_jiffies(100)))
|
||||
DSSERR("timeout waiting for FRAME DONE\n");
|
||||
|
||||
r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq);
|
||||
if (r)
|
||||
DSSERR("failed to unregister FRAMEDONE isr\n");
|
||||
}
|
||||
|
||||
static void dispc_digit_out_enable_isr(void *data, u32 mask)
|
||||
{
|
||||
struct completion *compl = data;
|
||||
|
||||
/* ignore any sync lost interrupts */
|
||||
if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
|
||||
complete(compl);
|
||||
}
|
||||
|
||||
static void dispc_mgr_enable_digit_out(void)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(vsync_compl);
|
||||
int r;
|
||||
u32 irq_mask;
|
||||
|
||||
if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Digit output produces some sync lost interrupts during the first
|
||||
* frame when enabling. Those need to be ignored, so we register for the
|
||||
* sync lost irq to prevent the error handler from triggering.
|
||||
*/
|
||||
|
||||
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
|
||||
dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
|
||||
|
||||
r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
|
||||
irq_mask);
|
||||
if (r) {
|
||||
DSSERR("failed to register %x isr\n", irq_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
|
||||
|
||||
/* wait for the first evsync */
|
||||
if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
|
||||
DSSERR("timeout waiting for digit out to start\n");
|
||||
|
||||
r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
|
||||
irq_mask);
|
||||
if (r)
|
||||
DSSERR("failed to unregister %x isr\n", irq_mask);
|
||||
}
|
||||
|
||||
static void dispc_mgr_disable_digit_out(void)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(framedone_compl);
|
||||
int r, i;
|
||||
u32 irq_mask;
|
||||
int num_irqs;
|
||||
|
||||
if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
|
||||
return;
|
||||
|
||||
/*
|
||||
* When we disable the digit output, we need to wait for FRAMEDONE to
|
||||
* know that DISPC has finished with the output.
|
||||
*/
|
||||
|
||||
irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
|
||||
num_irqs = 1;
|
||||
|
||||
if (!irq_mask) {
|
||||
/*
|
||||
* omap 2/3 don't have framedone irq for TV, so we need to use
|
||||
* vsyncs for this.
|
||||
*/
|
||||
|
||||
irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
|
||||
/*
|
||||
* We need to wait for both even and odd vsyncs. Note that this
|
||||
* is not totally reliable, as we could get a vsync interrupt
|
||||
* before we disable the output, which leads to timeout in the
|
||||
* wait_for_completion.
|
||||
*/
|
||||
num_irqs = 2;
|
||||
}
|
||||
|
||||
r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq_mask);
|
||||
if (r)
|
||||
DSSERR("failed to register %x isr\n", irq_mask);
|
||||
|
||||
dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
|
||||
|
||||
/* if we couldn't register the irq, just sleep and exit */
|
||||
if (r) {
|
||||
msleep(100);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_irqs; ++i) {
|
||||
if (!wait_for_completion_timeout(&framedone_compl,
|
||||
msecs_to_jiffies(100)))
|
||||
DSSERR("timeout waiting for digit out to stop\n");
|
||||
}
|
||||
|
||||
r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
|
||||
irq_mask);
|
||||
if (r)
|
||||
DSSERR("failed to unregister %x isr\n", irq_mask);
|
||||
}
|
||||
|
||||
void dispc_mgr_enable_sync(enum omap_channel channel)
|
||||
{
|
||||
if (dss_mgr_is_lcd(channel))
|
||||
dispc_mgr_enable_lcd_out(channel);
|
||||
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
|
||||
dispc_mgr_enable_digit_out();
|
||||
else
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
void dispc_mgr_disable_sync(enum omap_channel channel)
|
||||
{
|
||||
if (dss_mgr_is_lcd(channel))
|
||||
dispc_mgr_disable_lcd_out(channel);
|
||||
else if (channel == OMAP_DSS_CHANNEL_DIGIT)
|
||||
dispc_mgr_disable_digit_out();
|
||||
else
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static inline void dispc_irq_wait_handler(void *data, u32 mask)
|
||||
{
|
||||
complete((struct completion *)data);
|
||||
}
|
||||
|
||||
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
|
||||
unsigned long timeout)
|
||||
{
|
||||
|
||||
int r;
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
|
||||
r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
|
||||
irqmask);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
timeout = wait_for_completion_interruptible_timeout(&completion,
|
||||
timeout);
|
||||
|
||||
omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
|
||||
|
||||
if (timeout == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (timeout == -ERESTARTSYS)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Texas Instruments
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_DSS_DISPC_COMPAT_H
|
||||
#define __OMAP2_DSS_DISPC_COMPAT_H
|
||||
|
||||
void dispc_mgr_enable_sync(enum omap_channel channel);
|
||||
void dispc_mgr_disable_sync(enum omap_channel channel);
|
||||
|
||||
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
|
||||
unsigned long timeout);
|
||||
|
||||
int dss_dispc_initialize_irq(void);
|
||||
void dss_dispc_uninitialize_irq(void);
|
||||
|
||||
#endif
|
|
@ -104,6 +104,15 @@ struct dispc_features {
|
|||
bool supports_sync_align:1;
|
||||
|
||||
bool has_writeback:1;
|
||||
|
||||
bool supports_double_pixel:1;
|
||||
|
||||
/*
|
||||
* Field order for VENC is different than HDMI. We should handle this in
|
||||
* some intelligent manner, but as the SoCs have either HDMI or VENC,
|
||||
* never both, we can just use this flag for now.
|
||||
*/
|
||||
bool reverse_ilace_field_order:1;
|
||||
};
|
||||
|
||||
#define DISPC_MAX_NR_FIFOS 5
|
||||
|
@ -2552,47 +2561,6 @@ static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
|
||||
const struct omap_overlay_info *oi,
|
||||
const struct omap_video_timings *timings,
|
||||
int *x_predecim, int *y_predecim)
|
||||
{
|
||||
enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
|
||||
bool five_taps = true;
|
||||
bool fieldmode = false;
|
||||
u16 in_height = oi->height;
|
||||
u16 in_width = oi->width;
|
||||
bool ilace = timings->interlace;
|
||||
u16 out_width, out_height;
|
||||
int pos_x = oi->pos_x;
|
||||
unsigned long pclk = dispc_mgr_pclk_rate(channel);
|
||||
unsigned long lclk = dispc_mgr_lclk_rate(channel);
|
||||
|
||||
out_width = oi->out_width == 0 ? oi->width : oi->out_width;
|
||||
out_height = oi->out_height == 0 ? oi->height : oi->out_height;
|
||||
|
||||
if (ilace && oi->height == out_height)
|
||||
fieldmode = true;
|
||||
|
||||
if (ilace) {
|
||||
if (fieldmode)
|
||||
in_height /= 2;
|
||||
out_height /= 2;
|
||||
|
||||
DSSDBG("adjusting for ilace: height %d, out_height %d\n",
|
||||
in_height, out_height);
|
||||
}
|
||||
|
||||
if (!dss_feat_color_mode_supported(plane, oi->color_mode))
|
||||
return -EINVAL;
|
||||
|
||||
return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width,
|
||||
in_height, out_width, out_height, oi->color_mode,
|
||||
&five_taps, x_predecim, y_predecim, pos_x,
|
||||
oi->rotation_type, false);
|
||||
}
|
||||
EXPORT_SYMBOL(dispc_ovl_check);
|
||||
|
||||
static int dispc_ovl_setup_common(enum omap_plane plane,
|
||||
enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
|
||||
u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
|
||||
|
@ -2747,6 +2715,9 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
|
|||
|
||||
dispc_ovl_configure_burst_type(plane, rotation_type);
|
||||
|
||||
if (dispc.feat->reverse_ilace_field_order)
|
||||
swap(offset0, offset1);
|
||||
|
||||
dispc_ovl_set_ba0(plane, paddr + offset0);
|
||||
dispc_ovl_set_ba1(plane, paddr + offset1);
|
||||
|
||||
|
@ -2898,6 +2869,12 @@ bool dispc_ovl_enabled(enum omap_plane plane)
|
|||
}
|
||||
EXPORT_SYMBOL(dispc_ovl_enabled);
|
||||
|
||||
enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel)
|
||||
{
|
||||
return dss_feat_get_supported_outputs(channel);
|
||||
}
|
||||
EXPORT_SYMBOL(dispc_mgr_get_supported_outputs);
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable)
|
||||
{
|
||||
mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
|
||||
|
@ -3287,6 +3264,10 @@ void dispc_mgr_set_timings(enum omap_channel channel,
|
|||
} else {
|
||||
if (t.interlace)
|
||||
t.y_res /= 2;
|
||||
|
||||
if (dispc.feat->supports_double_pixel)
|
||||
REG_FLD_MOD(DISPC_CONTROL, t.double_pixel ? 1 : 0,
|
||||
19, 17);
|
||||
}
|
||||
|
||||
dispc_mgr_set_size(channel, t.x_res, t.y_res);
|
||||
|
@ -3951,6 +3932,8 @@ static const struct dispc_features omap44xx_dispc_feats = {
|
|||
.set_max_preload = true,
|
||||
.supports_sync_align = true,
|
||||
.has_writeback = true,
|
||||
.supports_double_pixel = true,
|
||||
.reverse_ilace_field_order = true,
|
||||
};
|
||||
|
||||
static const struct dispc_features omap54xx_dispc_feats = {
|
||||
|
@ -3974,6 +3957,8 @@ static const struct dispc_features omap54xx_dispc_feats = {
|
|||
.set_max_preload = true,
|
||||
.supports_sync_align = true,
|
||||
.has_writeback = true,
|
||||
.supports_double_pixel = true,
|
||||
.reverse_ilace_field_order = true,
|
||||
};
|
||||
|
||||
static int dispc_init_features(struct platform_device *pdev)
|
||||
|
@ -4129,8 +4114,6 @@ static int dispc_bind(struct device *dev, struct device *master, void *data)
|
|||
|
||||
dispc_runtime_put();
|
||||
|
||||
dss_init_overlay_managers();
|
||||
|
||||
dss_debugfs_create_file("dispc", dispc_dump_regs);
|
||||
|
||||
return 0;
|
||||
|
@ -4144,8 +4127,6 @@ static void dispc_unbind(struct device *dev, struct device *master,
|
|||
void *data)
|
||||
{
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
dss_uninit_overlay_managers();
|
||||
}
|
||||
|
||||
static const struct component_ops dispc_component_ops = {
|
||||
|
|
|
@ -1,356 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "DISPLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.h"
|
||||
|
||||
static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
dssdev->name ?
|
||||
dssdev->name : "");
|
||||
}
|
||||
|
||||
static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
omapdss_device_is_enabled(dssdev));
|
||||
}
|
||||
|
||||
static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
bool enable;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (enable == omapdss_device_is_enabled(dssdev))
|
||||
return size;
|
||||
|
||||
if (omapdss_device_is_connected(dssdev) == false)
|
||||
return -ENODEV;
|
||||
|
||||
if (enable) {
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
dssdev->driver->disable(dssdev);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
dssdev->driver->get_te ?
|
||||
dssdev->driver->get_te(dssdev) : 0);
|
||||
}
|
||||
|
||||
static ssize_t display_tear_store(struct omap_dss_device *dssdev,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
bool te;
|
||||
|
||||
if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
|
||||
return -ENOENT;
|
||||
|
||||
r = strtobool(buf, &te);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dssdev->driver->enable_te(dssdev, te);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
struct omap_video_timings t;
|
||||
|
||||
if (!dssdev->driver->get_timings)
|
||||
return -ENOENT;
|
||||
|
||||
dssdev->driver->get_timings(dssdev, &t);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
|
||||
t.pixelclock,
|
||||
t.x_res, t.hfp, t.hbp, t.hsw,
|
||||
t.y_res, t.vfp, t.vbp, t.vsw);
|
||||
}
|
||||
|
||||
static ssize_t display_timings_store(struct omap_dss_device *dssdev,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_video_timings t = dssdev->panel.timings;
|
||||
int r, found;
|
||||
|
||||
if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
|
||||
return -ENOENT;
|
||||
|
||||
found = 0;
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
if (strncmp("pal", buf, 3) == 0) {
|
||||
t = omap_dss_pal_timings;
|
||||
found = 1;
|
||||
} else if (strncmp("ntsc", buf, 4) == 0) {
|
||||
t = omap_dss_ntsc_timings;
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
|
||||
&t.pixelclock,
|
||||
&t.x_res, &t.hfp, &t.hbp, &t.hsw,
|
||||
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
|
||||
return -EINVAL;
|
||||
|
||||
r = dssdev->driver->check_timings(dssdev, &t);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->driver->disable(dssdev);
|
||||
dssdev->driver->set_timings(dssdev, &t);
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
int rotate;
|
||||
if (!dssdev->driver->get_rotate)
|
||||
return -ENOENT;
|
||||
rotate = dssdev->driver->get_rotate(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
|
||||
}
|
||||
|
||||
static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int rot, r;
|
||||
|
||||
if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
|
||||
return -ENOENT;
|
||||
|
||||
r = kstrtoint(buf, 0, &rot);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dssdev->driver->set_rotate(dssdev, rot);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
int mirror;
|
||||
if (!dssdev->driver->get_mirror)
|
||||
return -ENOENT;
|
||||
mirror = dssdev->driver->get_mirror(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
|
||||
}
|
||||
|
||||
static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
bool mirror;
|
||||
|
||||
if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
|
||||
return -ENOENT;
|
||||
|
||||
r = strtobool(buf, &mirror);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dssdev->driver->set_mirror(dssdev, mirror);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
|
||||
{
|
||||
unsigned int wss;
|
||||
|
||||
if (!dssdev->driver->get_wss)
|
||||
return -ENOENT;
|
||||
|
||||
wss = dssdev->driver->get_wss(dssdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
|
||||
}
|
||||
|
||||
static ssize_t display_wss_store(struct omap_dss_device *dssdev,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
u32 wss;
|
||||
int r;
|
||||
|
||||
if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
|
||||
return -ENOENT;
|
||||
|
||||
r = kstrtou32(buf, 0, &wss);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (wss > 0xfffff)
|
||||
return -EINVAL;
|
||||
|
||||
r = dssdev->driver->set_wss(dssdev, wss);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct display_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct omap_dss_device *, char *);
|
||||
ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define DISPLAY_ATTR(_name, _mode, _show, _store) \
|
||||
struct display_attribute display_attr_##_name = \
|
||||
__ATTR(_name, _mode, _show, _store)
|
||||
|
||||
static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
|
||||
static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
|
||||
static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
display_enabled_show, display_enabled_store);
|
||||
static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
|
||||
display_tear_show, display_tear_store);
|
||||
static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
|
||||
display_timings_show, display_timings_store);
|
||||
static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
|
||||
display_rotate_show, display_rotate_store);
|
||||
static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
|
||||
display_mirror_show, display_mirror_store);
|
||||
static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
|
||||
display_wss_show, display_wss_store);
|
||||
|
||||
static struct attribute *display_sysfs_attrs[] = {
|
||||
&display_attr_name.attr,
|
||||
&display_attr_display_name.attr,
|
||||
&display_attr_enabled.attr,
|
||||
&display_attr_tear_elim.attr,
|
||||
&display_attr_timings.attr,
|
||||
&display_attr_rotate.attr,
|
||||
&display_attr_mirror.attr,
|
||||
&display_attr_wss.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev;
|
||||
struct display_attribute *display_attr;
|
||||
|
||||
dssdev = container_of(kobj, struct omap_dss_device, kobj);
|
||||
display_attr = container_of(attr, struct display_attribute, attr);
|
||||
|
||||
if (!display_attr->show)
|
||||
return -ENOENT;
|
||||
|
||||
return display_attr->show(dssdev, buf);
|
||||
}
|
||||
|
||||
static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev;
|
||||
struct display_attribute *display_attr;
|
||||
|
||||
dssdev = container_of(kobj, struct omap_dss_device, kobj);
|
||||
display_attr = container_of(attr, struct display_attribute, attr);
|
||||
|
||||
if (!display_attr->store)
|
||||
return -ENOENT;
|
||||
|
||||
return display_attr->store(dssdev, buf, size);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops display_sysfs_ops = {
|
||||
.show = display_attr_show,
|
||||
.store = display_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type display_ktype = {
|
||||
.sysfs_ops = &display_sysfs_ops,
|
||||
.default_attrs = display_sysfs_attrs,
|
||||
};
|
||||
|
||||
int display_init_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
int r;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
|
||||
&pdev->dev.kobj, "%s", dssdev->alias);
|
||||
if (r) {
|
||||
DSSERR("failed to create sysfs files\n");
|
||||
omap_dss_put_device(dssdev);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
display_uninit_sysfs(pdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void display_uninit_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (kobject_name(&dssdev->kobj) == NULL)
|
||||
continue;
|
||||
|
||||
kobject_del(&dssdev->kobj);
|
||||
kobject_put(&dssdev->kobj);
|
||||
|
||||
memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
|
||||
}
|
||||
}
|
|
@ -78,55 +78,6 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_default_get_timings);
|
||||
|
||||
int dss_suspend_all_devices(void)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
dssdev->driver->disable(dssdev);
|
||||
dssdev->activate_after_resume = true;
|
||||
} else {
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_resume_all_devices(void)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->activate_after_resume) {
|
||||
dssdev->driver->enable(dssdev);
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_disable_all_devices(void)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
dssdev->driver->disable(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
static LIST_HEAD(panel_list);
|
||||
static DEFINE_MUTEX(panel_list_mutex);
|
||||
static int disp_num_counter;
|
||||
|
|
|
@ -334,7 +334,7 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
|
|||
static int dpi_set_mode(struct dpi_data *dpi)
|
||||
{
|
||||
struct omap_dss_device *out = &dpi->output;
|
||||
struct omap_overlay_manager *mgr = out->manager;
|
||||
enum omap_channel channel = out->dispc_channel;
|
||||
struct omap_video_timings *t = &dpi->timings;
|
||||
int lck_div = 0, pck_div = 0;
|
||||
unsigned long fck = 0;
|
||||
|
@ -342,7 +342,7 @@ static int dpi_set_mode(struct dpi_data *dpi)
|
|||
int r = 0;
|
||||
|
||||
if (dpi->pll)
|
||||
r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
|
||||
r = dpi_set_dsi_clk(dpi, channel, t->pixelclock, &fck,
|
||||
&lck_div, &pck_div);
|
||||
else
|
||||
r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
|
||||
|
@ -359,7 +359,7 @@ static int dpi_set_mode(struct dpi_data *dpi)
|
|||
t->pixelclock = pck;
|
||||
}
|
||||
|
||||
dss_mgr_set_timings(mgr, t);
|
||||
dss_mgr_set_timings(channel, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ static int dpi_set_mode(struct dpi_data *dpi)
|
|||
static void dpi_config_lcd_manager(struct dpi_data *dpi)
|
||||
{
|
||||
struct omap_dss_device *out = &dpi->output;
|
||||
struct omap_overlay_manager *mgr = out->manager;
|
||||
enum omap_channel channel = out->dispc_channel;
|
||||
|
||||
dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
|
||||
|
||||
|
@ -378,13 +378,14 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
|
|||
|
||||
dpi->mgr_config.lcden_sig_polarity = 0;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
|
||||
dss_mgr_set_lcd_config(channel, &dpi->mgr_config);
|
||||
}
|
||||
|
||||
static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
struct omap_dss_device *out = &dpi->output;
|
||||
enum omap_channel channel = out->dispc_channel;
|
||||
int r;
|
||||
|
||||
mutex_lock(&dpi->lock);
|
||||
|
@ -395,7 +396,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
goto err_no_reg;
|
||||
}
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err_no_out_mgr;
|
||||
|
@ -411,7 +412,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
r = dss_dpi_select_source(out->port_num, out->manager->id);
|
||||
r = dss_dpi_select_source(out->port_num, channel);
|
||||
if (r)
|
||||
goto err_src_sel;
|
||||
|
||||
|
@ -429,7 +430,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mdelay(2);
|
||||
|
||||
r = dss_mgr_enable(out->manager);
|
||||
r = dss_mgr_enable(channel);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
|
@ -457,14 +458,14 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
static void dpi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
struct omap_overlay_manager *mgr = dpi->output.manager;
|
||||
enum omap_channel channel = dpi->output.dispc_channel;
|
||||
|
||||
mutex_lock(&dpi->lock);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
dss_mgr_disable(channel);
|
||||
|
||||
if (dpi->pll) {
|
||||
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
||||
dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK);
|
||||
dss_pll_disable(dpi->pll);
|
||||
}
|
||||
|
||||
|
@ -506,14 +507,17 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
|
|||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
struct omap_overlay_manager *mgr = dpi->output.manager;
|
||||
enum omap_channel channel = dpi->output.dispc_channel;
|
||||
int lck_div, pck_div;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
struct dpi_clk_calc_ctx ctx;
|
||||
bool ok;
|
||||
|
||||
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
|
||||
if (timings->x_res % 8 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!dispc_mgr_timings_ok(channel, timings))
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->pixelclock == 0)
|
||||
|
@ -660,7 +664,7 @@ static int dpi_connect(struct omap_dss_device *dssdev,
|
|||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
struct omap_overlay_manager *mgr;
|
||||
enum omap_channel channel = dpi->output.dispc_channel;
|
||||
int r;
|
||||
|
||||
r = dpi_init_regulator(dpi);
|
||||
|
@ -669,11 +673,7 @@ static int dpi_connect(struct omap_dss_device *dssdev,
|
|||
|
||||
dpi_init_pll(dpi);
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
r = dss_mgr_connect(channel, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -681,7 +681,7 @@ static int dpi_connect(struct omap_dss_device *dssdev,
|
|||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -691,6 +691,9 @@ static int dpi_connect(struct omap_dss_device *dssdev,
|
|||
static void dpi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
enum omap_channel channel = dpi->output.dispc_channel;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
|
@ -698,8 +701,7 @@ static void dpi_disconnect(struct omap_dss_device *dssdev,
|
|||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_dpi_ops dpi_ops = {
|
||||
|
|
|
@ -214,9 +214,9 @@ struct dsi_reg { u16 module; u16 idx; };
|
|||
typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
|
||||
|
||||
static int dsi_display_init_dispc(struct platform_device *dsidev,
|
||||
struct omap_overlay_manager *mgr);
|
||||
enum omap_channel channel);
|
||||
static void dsi_display_uninit_dispc(struct platform_device *dsidev,
|
||||
struct omap_overlay_manager *mgr);
|
||||
enum omap_channel channel);
|
||||
|
||||
static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
|
||||
|
||||
|
@ -3826,19 +3826,19 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct omap_overlay_manager *mgr = dsi->output.manager;
|
||||
enum omap_channel dispc_channel = dssdev->dispc_channel;
|
||||
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
||||
struct omap_dss_device *out = &dsi->output;
|
||||
u8 data_type;
|
||||
u16 word_count;
|
||||
int r;
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = dsi_display_init_dispc(dsidev, mgr);
|
||||
r = dsi_display_init_dispc(dsidev, dispc_channel);
|
||||
if (r)
|
||||
goto err_init_dispc;
|
||||
|
||||
|
@ -3876,7 +3876,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|||
dsi_if_enable(dsidev, true);
|
||||
}
|
||||
|
||||
r = dss_mgr_enable(mgr);
|
||||
r = dss_mgr_enable(dispc_channel);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
|
@ -3888,7 +3888,7 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|||
dsi_vc_enable(dsidev, channel, false);
|
||||
}
|
||||
err_pix_fmt:
|
||||
dsi_display_uninit_dispc(dsidev, mgr);
|
||||
dsi_display_uninit_dispc(dsidev, dispc_channel);
|
||||
err_init_dispc:
|
||||
return r;
|
||||
}
|
||||
|
@ -3897,7 +3897,7 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel
|
|||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct omap_overlay_manager *mgr = dsi->output.manager;
|
||||
enum omap_channel dispc_channel = dssdev->dispc_channel;
|
||||
|
||||
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
||||
dsi_if_enable(dsidev, false);
|
||||
|
@ -3910,15 +3910,15 @@ static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel
|
|||
dsi_if_enable(dsidev, true);
|
||||
}
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
dss_mgr_disable(dispc_channel);
|
||||
|
||||
dsi_display_uninit_dispc(dsidev, mgr);
|
||||
dsi_display_uninit_dispc(dsidev, dispc_channel);
|
||||
}
|
||||
|
||||
static void dsi_update_screen_dispc(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct omap_overlay_manager *mgr = dsi->output.manager;
|
||||
enum omap_channel dispc_channel = dsi->output.dispc_channel;
|
||||
unsigned bytespp;
|
||||
unsigned bytespl;
|
||||
unsigned bytespf;
|
||||
|
@ -3980,9 +3980,9 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev)
|
|||
msecs_to_jiffies(250));
|
||||
BUG_ON(r == 0);
|
||||
|
||||
dss_mgr_set_timings(mgr, &dsi->timings);
|
||||
dss_mgr_set_timings(dispc_channel, &dsi->timings);
|
||||
|
||||
dss_mgr_start_update(mgr);
|
||||
dss_mgr_start_update(dispc_channel);
|
||||
|
||||
if (dsi->te_enabled) {
|
||||
/* disable LP_RX_TO, so that we can receive TE. Time to wait
|
||||
|
@ -4105,17 +4105,17 @@ static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
|
|||
}
|
||||
|
||||
static int dsi_display_init_dispc(struct platform_device *dsidev,
|
||||
struct omap_overlay_manager *mgr)
|
||||
enum omap_channel channel)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
int r;
|
||||
|
||||
dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
|
||||
dss_select_lcd_clk_source(channel, dsi->module_id == 0 ?
|
||||
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
|
||||
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
|
||||
|
||||
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
|
||||
r = dss_mgr_register_framedone_handler(mgr,
|
||||
r = dss_mgr_register_framedone_handler(channel,
|
||||
dsi_framedone_irq_callback, dsidev);
|
||||
if (r) {
|
||||
DSSERR("can't register FRAMEDONE handler\n");
|
||||
|
@ -4140,7 +4140,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev,
|
|||
dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
|
||||
dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE;
|
||||
|
||||
dss_mgr_set_timings(mgr, &dsi->timings);
|
||||
dss_mgr_set_timings(channel, &dsi->timings);
|
||||
|
||||
r = dsi_configure_dispc_clocks(dsidev);
|
||||
if (r)
|
||||
|
@ -4151,28 +4151,28 @@ static int dsi_display_init_dispc(struct platform_device *dsidev,
|
|||
dsi_get_pixel_size(dsi->pix_fmt);
|
||||
dsi->mgr_config.lcden_sig_polarity = 0;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
|
||||
dss_mgr_set_lcd_config(channel, &dsi->mgr_config);
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
|
||||
dss_mgr_unregister_framedone_handler(mgr,
|
||||
dss_mgr_unregister_framedone_handler(channel,
|
||||
dsi_framedone_irq_callback, dsidev);
|
||||
err:
|
||||
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
||||
dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dsi_display_uninit_dispc(struct platform_device *dsidev,
|
||||
struct omap_overlay_manager *mgr)
|
||||
enum omap_channel channel)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
|
||||
dss_mgr_unregister_framedone_handler(mgr,
|
||||
dss_mgr_unregister_framedone_handler(channel,
|
||||
dsi_framedone_irq_callback, dsidev);
|
||||
|
||||
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
||||
dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK);
|
||||
}
|
||||
|
||||
static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
|
||||
|
@ -4983,18 +4983,14 @@ static int dsi_connect(struct omap_dss_device *dssdev,
|
|||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
struct omap_overlay_manager *mgr;
|
||||
enum omap_channel dispc_channel = dssdev->dispc_channel;
|
||||
int r;
|
||||
|
||||
r = dsi_regulator_init(dsidev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
r = dss_mgr_connect(dispc_channel, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -5002,7 +4998,7 @@ static int dsi_connect(struct omap_dss_device *dssdev,
|
|||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dssdev->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
dss_mgr_disconnect(dispc_channel, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -5012,6 +5008,8 @@ static int dsi_connect(struct omap_dss_device *dssdev,
|
|||
static void dsi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
enum omap_channel dispc_channel = dssdev->dispc_channel;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
|
@ -5019,8 +5017,7 @@ static void dsi_disconnect(struct omap_dss_device *dssdev,
|
|||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
dss_mgr_disconnect(dispc_channel, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_dsi_ops dsi_ops = {
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
@ -205,29 +207,6 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
|
|||
int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
|
||||
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
|
||||
|
||||
/* display */
|
||||
int dss_suspend_all_devices(void);
|
||||
int dss_resume_all_devices(void);
|
||||
void dss_disable_all_devices(void);
|
||||
|
||||
int display_init_sysfs(struct platform_device *pdev);
|
||||
void display_uninit_sysfs(struct platform_device *pdev);
|
||||
|
||||
/* manager */
|
||||
int dss_init_overlay_managers(void);
|
||||
void dss_uninit_overlay_managers(void);
|
||||
int dss_init_overlay_managers_sysfs(struct platform_device *pdev);
|
||||
void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev);
|
||||
int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
|
||||
const struct omap_overlay_manager_info *info);
|
||||
int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings);
|
||||
int dss_mgr_check(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_manager_info *info,
|
||||
const struct omap_video_timings *mgr_timings,
|
||||
const struct dss_lcd_mgr_config *config,
|
||||
struct omap_overlay_info **overlay_infos);
|
||||
|
||||
static inline bool dss_mgr_is_lcd(enum omap_channel id)
|
||||
{
|
||||
if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 ||
|
||||
|
@ -237,24 +216,6 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id)
|
|||
return false;
|
||||
}
|
||||
|
||||
int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
|
||||
struct platform_device *pdev);
|
||||
void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
|
||||
|
||||
/* overlay */
|
||||
void dss_init_overlays(struct platform_device *pdev);
|
||||
void dss_uninit_overlays(struct platform_device *pdev);
|
||||
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
|
||||
int dss_ovl_simple_check(struct omap_overlay *ovl,
|
||||
const struct omap_overlay_info *info);
|
||||
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
|
||||
const struct omap_video_timings *mgr_timings);
|
||||
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
|
||||
enum omap_color_mode mode);
|
||||
int dss_overlay_kobj_init(struct omap_overlay *ovl,
|
||||
struct platform_device *pdev);
|
||||
void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
|
||||
|
||||
/* DSS */
|
||||
int dss_init_platform_driver(void) __init;
|
||||
void dss_uninit_platform_driver(void);
|
||||
|
|
|
@ -165,9 +165,10 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
{
|
||||
int r;
|
||||
struct omap_video_timings *p;
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
struct hdmi_wp_data *wp = &hdmi.wp;
|
||||
struct dss_pll_clock_info hdmi_cinfo = { 0 };
|
||||
unsigned pc;
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
if (r)
|
||||
|
@ -181,7 +182,11 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
|
||||
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
|
||||
pc = p->pixelclock;
|
||||
if (p->double_pixel)
|
||||
pc *= 2;
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo);
|
||||
|
||||
r = dss_pll_enable(&hdmi.pll.pll);
|
||||
if (r) {
|
||||
|
@ -212,24 +217,24 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
dispc_enable_gamma_table(0);
|
||||
|
||||
/* tv size */
|
||||
dss_mgr_set_timings(mgr, p);
|
||||
dss_mgr_set_timings(channel, p);
|
||||
|
||||
r = dss_mgr_enable(channel);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
r = hdmi_wp_video_start(&hdmi.wp);
|
||||
if (r)
|
||||
goto err_vid_enable;
|
||||
|
||||
r = dss_mgr_enable(mgr);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
hdmi_wp_set_irqenable(wp,
|
||||
HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
|
||||
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
hdmi_wp_video_stop(&hdmi.wp);
|
||||
err_vid_enable:
|
||||
dss_mgr_disable(channel);
|
||||
err_mgr_enable:
|
||||
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
|
||||
err_phy_pwr:
|
||||
err_phy_cfg:
|
||||
|
@ -242,14 +247,14 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
|
||||
static void hdmi_power_off_full(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
hdmi_wp_video_stop(&hdmi.wp);
|
||||
|
||||
dss_mgr_disable(channel);
|
||||
|
||||
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
|
||||
|
||||
dss_pll_disable(&hdmi.pll.pll);
|
||||
|
@ -260,9 +265,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
|
|||
static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
|
||||
if (!dispc_mgr_timings_ok(dssdev->dispc_channel, timings))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -343,7 +346,7 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
|
@ -433,18 +436,14 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
|
|||
static int hdmi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
int r;
|
||||
|
||||
r = hdmi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
r = dss_mgr_connect(channel, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -452,7 +451,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev,
|
|||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -462,6 +461,8 @@ static int hdmi_connect(struct omap_dss_device *dssdev,
|
|||
static void hdmi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
|
@ -469,8 +470,7 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev,
|
|||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
}
|
||||
|
||||
static int hdmi_read_edid(struct omap_dss_device *dssdev,
|
||||
|
|
|
@ -182,8 +182,9 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
{
|
||||
int r;
|
||||
struct omap_video_timings *p;
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
struct dss_pll_clock_info hdmi_cinfo = { 0 };
|
||||
unsigned pc;
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
if (r)
|
||||
|
@ -193,7 +194,11 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
|
||||
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
|
||||
pc = p->pixelclock;
|
||||
if (p->double_pixel)
|
||||
pc *= 2;
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo);
|
||||
|
||||
/* disable and clear irqs */
|
||||
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
|
||||
|
@ -229,24 +234,24 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
dispc_enable_gamma_table(0);
|
||||
|
||||
/* tv size */
|
||||
dss_mgr_set_timings(mgr, p);
|
||||
dss_mgr_set_timings(channel, p);
|
||||
|
||||
r = dss_mgr_enable(channel);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
r = hdmi_wp_video_start(&hdmi.wp);
|
||||
if (r)
|
||||
goto err_vid_enable;
|
||||
|
||||
r = dss_mgr_enable(mgr);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
hdmi_wp_set_irqenable(&hdmi.wp,
|
||||
HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
|
||||
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
hdmi_wp_video_stop(&hdmi.wp);
|
||||
err_vid_enable:
|
||||
dss_mgr_disable(channel);
|
||||
err_mgr_enable:
|
||||
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
|
||||
err_phy_pwr:
|
||||
err_phy_cfg:
|
||||
|
@ -259,14 +264,14 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
|||
|
||||
static void hdmi_power_off_full(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
|
||||
hdmi_wp_video_stop(&hdmi.wp);
|
||||
|
||||
dss_mgr_disable(channel);
|
||||
|
||||
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
|
||||
|
||||
dss_pll_disable(&hdmi.pll.pll);
|
||||
|
@ -277,13 +282,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
|
|||
static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
|
||||
/* TODO: proper interlace support */
|
||||
if (timings->interlace)
|
||||
return -EINVAL;
|
||||
|
||||
if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
|
||||
if (!dispc_mgr_timings_ok(dssdev->dispc_channel, timings))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -373,7 +372,7 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
|
@ -463,18 +462,14 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
|
|||
static int hdmi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
int r;
|
||||
|
||||
r = hdmi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
r = dss_mgr_connect(channel, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -482,7 +477,7 @@ static int hdmi_connect(struct omap_dss_device *dssdev,
|
|||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -492,6 +487,8 @@ static int hdmi_connect(struct omap_dss_device *dssdev,
|
|||
static void hdmi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
|
@ -499,8 +496,7 @@ static void hdmi_disconnect(struct omap_dss_device *dssdev,
|
|||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
}
|
||||
|
||||
static int hdmi_read_edid(struct omap_dss_device *dssdev,
|
||||
|
|
|
@ -292,25 +292,36 @@ static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
|
|||
{
|
||||
DSSDBG("hdmi_core_init\n");
|
||||
|
||||
video_cfg->v_fc_config.timings = cfg->timings;
|
||||
|
||||
/* video core */
|
||||
video_cfg->data_enable_pol = 1; /* It is always 1*/
|
||||
video_cfg->v_fc_config.timings.hsync_level = cfg->timings.hsync_level;
|
||||
video_cfg->v_fc_config.timings.x_res = cfg->timings.x_res;
|
||||
video_cfg->v_fc_config.timings.hsw = cfg->timings.hsw - 1;
|
||||
video_cfg->v_fc_config.timings.hbp = cfg->timings.hbp;
|
||||
video_cfg->v_fc_config.timings.hfp = cfg->timings.hfp;
|
||||
video_cfg->hblank = cfg->timings.hfp +
|
||||
cfg->timings.hbp + cfg->timings.hsw - 1;
|
||||
video_cfg->v_fc_config.timings.vsync_level = cfg->timings.vsync_level;
|
||||
video_cfg->v_fc_config.timings.y_res = cfg->timings.y_res;
|
||||
video_cfg->v_fc_config.timings.vsw = cfg->timings.vsw;
|
||||
video_cfg->v_fc_config.timings.vfp = cfg->timings.vfp;
|
||||
video_cfg->v_fc_config.timings.vbp = cfg->timings.vbp;
|
||||
video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */
|
||||
cfg->timings.hbp + cfg->timings.hsw;
|
||||
video_cfg->vblank_osc = 0;
|
||||
video_cfg->vblank = cfg->timings.vsw +
|
||||
cfg->timings.vfp + cfg->timings.vbp;
|
||||
video_cfg->v_fc_config.hdmi_dvi_mode = cfg->hdmi_dvi_mode;
|
||||
video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace;
|
||||
|
||||
if (cfg->timings.interlace) {
|
||||
/* set vblank_osc if vblank is fractional */
|
||||
if (video_cfg->vblank % 2 != 0)
|
||||
video_cfg->vblank_osc = 1;
|
||||
|
||||
video_cfg->v_fc_config.timings.y_res /= 2;
|
||||
video_cfg->vblank /= 2;
|
||||
video_cfg->v_fc_config.timings.vfp /= 2;
|
||||
video_cfg->v_fc_config.timings.vsw /= 2;
|
||||
video_cfg->v_fc_config.timings.vbp /= 2;
|
||||
}
|
||||
|
||||
if (cfg->timings.double_pixel) {
|
||||
video_cfg->v_fc_config.timings.x_res *= 2;
|
||||
video_cfg->hblank *= 2;
|
||||
video_cfg->v_fc_config.timings.hfp *= 2;
|
||||
video_cfg->v_fc_config.timings.hsw *= 2;
|
||||
video_cfg->v_fc_config.timings.hbp *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* DSS_HDMI_CORE_VIDEO_CONFIG */
|
||||
|
@ -377,6 +388,11 @@ static void hdmi_core_video_config(struct hdmi_core_data *core,
|
|||
/* select DVI mode */
|
||||
REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF,
|
||||
cfg->v_fc_config.hdmi_dvi_mode, 3, 3);
|
||||
|
||||
if (cfg->v_fc_config.timings.double_pixel)
|
||||
REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, 2, 7, 4);
|
||||
else
|
||||
REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, 1, 7, 4);
|
||||
}
|
||||
|
||||
static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core)
|
||||
|
|
|
@ -165,12 +165,24 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
|
|||
{
|
||||
u32 timing_h = 0;
|
||||
u32 timing_v = 0;
|
||||
unsigned hsw_offset = 1;
|
||||
|
||||
DSSDBG("Enter hdmi_wp_video_config_timing\n");
|
||||
|
||||
/*
|
||||
* On OMAP4 and OMAP5 ES1 the HSW field is programmed as is. On OMAP5
|
||||
* ES2+ (including DRA7/AM5 SoCs) HSW field is programmed to hsw-1.
|
||||
* However, we don't support OMAP5 ES1 at all, so we can just check for
|
||||
* OMAP4 here.
|
||||
*/
|
||||
if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
|
||||
omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
|
||||
omapdss_get_version() == OMAPDSS_VER_OMAP4)
|
||||
hsw_offset = 0;
|
||||
|
||||
timing_h |= FLD_VAL(timings->hbp, 31, 20);
|
||||
timing_h |= FLD_VAL(timings->hfp, 19, 8);
|
||||
timing_h |= FLD_VAL(timings->hsw, 7, 0);
|
||||
timing_h |= FLD_VAL(timings->hsw - hsw_offset, 7, 0);
|
||||
hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
|
||||
|
||||
timing_v |= FLD_VAL(timings->vbp, 31, 20);
|
||||
|
@ -187,8 +199,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
|
|||
video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
|
||||
video_fmt->y_res = param->timings.y_res;
|
||||
video_fmt->x_res = param->timings.x_res;
|
||||
if (param->timings.interlace)
|
||||
video_fmt->y_res /= 2;
|
||||
|
||||
timings->hbp = param->timings.hbp;
|
||||
timings->hfp = param->timings.hfp;
|
||||
|
@ -196,9 +206,25 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
|
|||
timings->vbp = param->timings.vbp;
|
||||
timings->vfp = param->timings.vfp;
|
||||
timings->vsw = param->timings.vsw;
|
||||
|
||||
timings->vsync_level = param->timings.vsync_level;
|
||||
timings->hsync_level = param->timings.hsync_level;
|
||||
timings->interlace = param->timings.interlace;
|
||||
timings->double_pixel = param->timings.double_pixel;
|
||||
|
||||
if (param->timings.interlace) {
|
||||
video_fmt->y_res /= 2;
|
||||
timings->vbp /= 2;
|
||||
timings->vfp /= 2;
|
||||
timings->vsw /= 2;
|
||||
}
|
||||
|
||||
if (param->timings.double_pixel) {
|
||||
video_fmt->x_res *= 2;
|
||||
timings->hfp *= 2;
|
||||
timings->hsw *= 2;
|
||||
timings->hbp *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
|
||||
|
|
|
@ -1,531 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "MANAGER"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
|
||||
}
|
||||
|
||||
static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = mgr->get_device(mgr);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
|
||||
dssdev->name : "<none>");
|
||||
}
|
||||
|
||||
static int manager_display_match(struct omap_dss_device *dssdev, void *data)
|
||||
{
|
||||
const char *str = data;
|
||||
|
||||
return sysfs_streq(dssdev->name, str);
|
||||
}
|
||||
|
||||
static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r = 0;
|
||||
size_t len = size;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
struct omap_dss_device *old_dssdev;
|
||||
|
||||
if (buf[size-1] == '\n')
|
||||
--len;
|
||||
|
||||
if (len > 0)
|
||||
dssdev = omap_dss_find_device((void *)buf,
|
||||
manager_display_match);
|
||||
|
||||
if (len > 0 && dssdev == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (dssdev) {
|
||||
DSSDBG("display %s found\n", dssdev->name);
|
||||
|
||||
if (omapdss_device_is_connected(dssdev)) {
|
||||
DSSERR("new display is already connected\n");
|
||||
r = -EINVAL;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev)) {
|
||||
DSSERR("new display is not disabled\n");
|
||||
r = -EINVAL;
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
old_dssdev = mgr->get_device(mgr);
|
||||
if (old_dssdev) {
|
||||
if (omapdss_device_is_enabled(old_dssdev)) {
|
||||
DSSERR("old display is not disabled\n");
|
||||
r = -EINVAL;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
old_dssdev->driver->disconnect(old_dssdev);
|
||||
}
|
||||
|
||||
if (dssdev) {
|
||||
r = dssdev->driver->connect(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to connect new device\n");
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
old_dssdev = mgr->get_device(mgr);
|
||||
if (old_dssdev != dssdev) {
|
||||
DSSERR("failed to connect device to this manager\n");
|
||||
dssdev->driver->disconnect(dssdev);
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r) {
|
||||
DSSERR("failed to apply dispc config\n");
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
put_device:
|
||||
if (dssdev)
|
||||
omap_dss_put_device(dssdev);
|
||||
|
||||
return r ? r : size;
|
||||
}
|
||||
|
||||
static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
|
||||
}
|
||||
|
||||
static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
u32 color;
|
||||
int r;
|
||||
|
||||
r = kstrtouint(buf, 0, &color);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.default_color = color;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static const char *trans_key_type_str[] = {
|
||||
"gfx-destination",
|
||||
"video-source",
|
||||
};
|
||||
|
||||
static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
enum omap_dss_trans_key_type key_type;
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
key_type = info.trans_key_type;
|
||||
BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
enum omap_dss_trans_key_type key_type;
|
||||
struct omap_overlay_manager_info info;
|
||||
int r;
|
||||
|
||||
for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
|
||||
key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
|
||||
if (sysfs_streq(buf, trans_key_type_str[key_type]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (key_type == ARRAY_SIZE(trans_key_type_str))
|
||||
return -EINVAL;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.trans_key_type = key_type;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
u32 key_value;
|
||||
int r;
|
||||
|
||||
r = kstrtouint(buf, 0, &key_value);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.trans_key = key_value;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
|
||||
}
|
||||
|
||||
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;
|
||||
bool enable;
|
||||
int r;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.trans_enabled = enable;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_alpha_blending_enabled_show(
|
||||
struct omap_overlay_manager *mgr, char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
|
||||
return -ENODEV;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
info.partial_alpha_enabled);
|
||||
}
|
||||
|
||||
static ssize_t manager_alpha_blending_enabled_store(
|
||||
struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
bool enable;
|
||||
int r;
|
||||
|
||||
if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
|
||||
return -ENODEV;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.partial_alpha_enabled = enable;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
|
||||
}
|
||||
|
||||
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 r;
|
||||
bool enable;
|
||||
|
||||
if (!dss_has_feature(FEAT_CPR))
|
||||
return -ENODEV;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
if (info.cpr_enable == enable)
|
||||
return size;
|
||||
|
||||
info.cpr_enable = enable;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE,
|
||||
"%d %d %d %d %d %d %d %d %d\n",
|
||||
info.cpr_coefs.rr,
|
||||
info.cpr_coefs.rg,
|
||||
info.cpr_coefs.rb,
|
||||
info.cpr_coefs.gr,
|
||||
info.cpr_coefs.gg,
|
||||
info.cpr_coefs.gb,
|
||||
info.cpr_coefs.br,
|
||||
info.cpr_coefs.bg,
|
||||
info.cpr_coefs.bb);
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
struct omap_dss_cpr_coefs coefs;
|
||||
int r, i;
|
||||
s16 *arr;
|
||||
|
||||
if (!dss_has_feature(FEAT_CPR))
|
||||
return -ENODEV;
|
||||
|
||||
if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
|
||||
&coefs.rr, &coefs.rg, &coefs.rb,
|
||||
&coefs.gr, &coefs.gg, &coefs.gb,
|
||||
&coefs.br, &coefs.bg, &coefs.bb) != 9)
|
||||
return -EINVAL;
|
||||
|
||||
arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
|
||||
coefs.gr, coefs.gg, coefs.gb,
|
||||
coefs.br, coefs.bg, coefs.bb };
|
||||
|
||||
for (i = 0; i < 9; ++i) {
|
||||
if (arr[i] < -512 || arr[i] > 511)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
info.cpr_coefs = coefs;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct manager_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct omap_overlay_manager *, char *);
|
||||
ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define MANAGER_ATTR(_name, _mode, _show, _store) \
|
||||
struct manager_attribute manager_attr_##_name = \
|
||||
__ATTR(_name, _mode, _show, _store)
|
||||
|
||||
static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
|
||||
static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
|
||||
manager_display_show, manager_display_store);
|
||||
static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
|
||||
manager_default_color_show, manager_default_color_store);
|
||||
static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
|
||||
manager_trans_key_type_show, manager_trans_key_type_store);
|
||||
static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
|
||||
manager_trans_key_value_show, manager_trans_key_value_store);
|
||||
static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
|
||||
manager_trans_key_enabled_show,
|
||||
manager_trans_key_enabled_store);
|
||||
static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
|
||||
manager_alpha_blending_enabled_show,
|
||||
manager_alpha_blending_enabled_store);
|
||||
static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
|
||||
manager_cpr_enable_show,
|
||||
manager_cpr_enable_store);
|
||||
static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
|
||||
manager_cpr_coef_show,
|
||||
manager_cpr_coef_store);
|
||||
|
||||
|
||||
static struct attribute *manager_sysfs_attrs[] = {
|
||||
&manager_attr_name.attr,
|
||||
&manager_attr_display.attr,
|
||||
&manager_attr_default_color.attr,
|
||||
&manager_attr_trans_key_type.attr,
|
||||
&manager_attr_trans_key_value.attr,
|
||||
&manager_attr_trans_key_enabled.attr,
|
||||
&manager_attr_alpha_blending_enabled.attr,
|
||||
&manager_attr_cpr_enable.attr,
|
||||
&manager_attr_cpr_coef.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_manager *manager;
|
||||
struct manager_attribute *manager_attr;
|
||||
|
||||
manager = container_of(kobj, struct omap_overlay_manager, kobj);
|
||||
manager_attr = container_of(attr, struct manager_attribute, attr);
|
||||
|
||||
if (!manager_attr->show)
|
||||
return -ENOENT;
|
||||
|
||||
return manager_attr->show(manager, buf);
|
||||
}
|
||||
|
||||
static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay_manager *manager;
|
||||
struct manager_attribute *manager_attr;
|
||||
|
||||
manager = container_of(kobj, struct omap_overlay_manager, kobj);
|
||||
manager_attr = container_of(attr, struct manager_attribute, attr);
|
||||
|
||||
if (!manager_attr->store)
|
||||
return -ENOENT;
|
||||
|
||||
return manager_attr->store(manager, buf, size);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops manager_sysfs_ops = {
|
||||
.show = manager_attr_show,
|
||||
.store = manager_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type manager_ktype = {
|
||||
.sysfs_ops = &manager_sysfs_ops,
|
||||
.default_attrs = manager_sysfs_attrs,
|
||||
};
|
||||
|
||||
int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return kobject_init_and_add(&mgr->kobj, &manager_ktype,
|
||||
&pdev->dev.kobj, "manager%d", mgr->id);
|
||||
}
|
||||
|
||||
void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
kobject_del(&mgr->kobj);
|
||||
kobject_put(&mgr->kobj);
|
||||
|
||||
memset(&mgr->kobj, 0, sizeof(mgr->kobj));
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
/*
|
||||
* linux/drivers/video/omap2/dss/manager.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "MANAGER"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static int num_managers;
|
||||
static struct omap_overlay_manager *managers;
|
||||
|
||||
int dss_init_overlay_managers(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
num_managers = dss_feat_get_num_mgrs();
|
||||
|
||||
managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
|
||||
GFP_KERNEL);
|
||||
|
||||
BUG_ON(managers == NULL);
|
||||
|
||||
for (i = 0; i < num_managers; ++i) {
|
||||
struct omap_overlay_manager *mgr = &managers[i];
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
mgr->name = "lcd";
|
||||
mgr->id = OMAP_DSS_CHANNEL_LCD;
|
||||
break;
|
||||
case 1:
|
||||
mgr->name = "tv";
|
||||
mgr->id = OMAP_DSS_CHANNEL_DIGIT;
|
||||
break;
|
||||
case 2:
|
||||
mgr->name = "lcd2";
|
||||
mgr->id = OMAP_DSS_CHANNEL_LCD2;
|
||||
break;
|
||||
case 3:
|
||||
mgr->name = "lcd3";
|
||||
mgr->id = OMAP_DSS_CHANNEL_LCD3;
|
||||
break;
|
||||
}
|
||||
|
||||
mgr->caps = 0;
|
||||
mgr->supported_displays =
|
||||
dss_feat_get_supported_displays(mgr->id);
|
||||
mgr->supported_outputs =
|
||||
dss_feat_get_supported_outputs(mgr->id);
|
||||
|
||||
INIT_LIST_HEAD(&mgr->overlays);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < num_managers; ++i) {
|
||||
struct omap_overlay_manager *mgr = &managers[i];
|
||||
|
||||
r = dss_manager_kobj_init(mgr, pdev);
|
||||
if (r)
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_uninit_overlay_managers(void)
|
||||
{
|
||||
kfree(managers);
|
||||
managers = NULL;
|
||||
num_managers = 0;
|
||||
}
|
||||
|
||||
void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_managers; ++i) {
|
||||
struct omap_overlay_manager *mgr = &managers[i];
|
||||
|
||||
dss_manager_kobj_uninit(mgr);
|
||||
}
|
||||
}
|
||||
|
||||
int omap_dss_get_num_overlay_managers(void)
|
||||
{
|
||||
return num_managers;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
|
||||
|
||||
struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
|
||||
{
|
||||
if (num >= num_managers)
|
||||
return NULL;
|
||||
|
||||
return &managers[num];
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_overlay_manager);
|
||||
|
||||
int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
|
||||
const struct omap_overlay_manager_info *info)
|
||||
{
|
||||
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 (info->partial_alpha_enabled && info->trans_enabled
|
||||
&& info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
|
||||
DSSERR("check_manager: illegal transparency key\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_info **overlay_infos)
|
||||
{
|
||||
struct omap_overlay *ovl1, *ovl2;
|
||||
struct omap_overlay_info *info1, *info2;
|
||||
|
||||
list_for_each_entry(ovl1, &mgr->overlays, list) {
|
||||
info1 = overlay_infos[ovl1->id];
|
||||
|
||||
if (info1 == NULL)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(ovl2, &mgr->overlays, list) {
|
||||
if (ovl1 == ovl2)
|
||||
continue;
|
||||
|
||||
info2 = overlay_infos[ovl2->id];
|
||||
|
||||
if (info2 == NULL)
|
||||
continue;
|
||||
|
||||
if (info1->zorder == info2->zorder) {
|
||||
DSSERR("overlays %d and %d have the same "
|
||||
"zorder %d\n",
|
||||
ovl1->id, ovl2->id, info1->zorder);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings)
|
||||
{
|
||||
if (!dispc_mgr_timings_ok(mgr->id, timings)) {
|
||||
DSSERR("check_manager: invalid timings\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config)
|
||||
{
|
||||
struct dispc_clock_info cinfo = config->clock_info;
|
||||
int dl = config->video_port_width;
|
||||
bool stallmode = config->stallmode;
|
||||
bool fifohandcheck = config->fifohandcheck;
|
||||
|
||||
if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
|
||||
return -EINVAL;
|
||||
|
||||
/* fifohandcheck should be used only with stallmode */
|
||||
if (!stallmode && fifohandcheck)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* io pad mode can be only checked by using dssdev connected to the
|
||||
* manager. Ignore checking these for now, add checks when manager
|
||||
* is capable of holding information related to the connected interface
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_mgr_check(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_manager_info *info,
|
||||
const struct omap_video_timings *mgr_timings,
|
||||
const struct dss_lcd_mgr_config *lcd_config,
|
||||
struct omap_overlay_info **overlay_infos)
|
||||
{
|
||||
struct omap_overlay *ovl;
|
||||
int r;
|
||||
|
||||
if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
|
||||
r = dss_mgr_check_zorder(mgr, overlay_infos);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dss_mgr_check_timings(mgr, mgr_timings);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dss_mgr_check_lcd_config(mgr, lcd_config);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
list_for_each_entry(ovl, &mgr->overlays, list) {
|
||||
struct omap_overlay_info *oi;
|
||||
int r;
|
||||
|
||||
oi = overlay_infos[ovl->id];
|
||||
|
||||
if (oi == NULL)
|
||||
continue;
|
||||
|
||||
r = dss_ovl_check(ovl, oi, mgr_timings);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Texas Instruments
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP_DRM_DSS_H
|
||||
#define __OMAP_DRM_DSS_H
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
u32 dispc_read_irqstatus(void);
|
||||
void dispc_clear_irqstatus(u32 mask);
|
||||
u32 dispc_read_irqenable(void);
|
||||
void dispc_write_irqenable(u32 mask);
|
||||
|
||||
int dispc_request_irq(irq_handler_t handler, void *dev_id);
|
||||
void dispc_free_irq(void *dev_id);
|
||||
|
||||
int dispc_runtime_get(void);
|
||||
void dispc_runtime_put(void);
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable);
|
||||
bool dispc_mgr_is_enabled(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel);
|
||||
bool dispc_mgr_go_busy(enum omap_channel channel);
|
||||
void dispc_mgr_go(enum omap_channel channel);
|
||||
void dispc_mgr_set_lcd_config(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
void dispc_mgr_set_timings(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings);
|
||||
void dispc_mgr_setup(enum omap_channel channel,
|
||||
const struct omap_overlay_manager_info *info);
|
||||
|
||||
int dispc_ovl_enable(enum omap_plane plane, bool enable);
|
||||
bool dispc_ovl_enabled(enum omap_plane plane);
|
||||
void dispc_ovl_set_channel_out(enum omap_plane plane,
|
||||
enum omap_channel channel);
|
||||
int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
|
||||
bool replication, const struct omap_video_timings *mgr_timings,
|
||||
bool mem_to_mem);
|
||||
|
||||
enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel);
|
||||
|
||||
struct dss_mgr_ops {
|
||||
int (*connect)(enum omap_channel channel,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(enum omap_channel channel,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
void (*start_update)(enum omap_channel channel);
|
||||
int (*enable)(enum omap_channel channel);
|
||||
void (*disable)(enum omap_channel channel);
|
||||
void (*set_timings)(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings);
|
||||
void (*set_lcd_config)(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
int (*register_framedone_handler)(enum omap_channel channel,
|
||||
void (*handler)(void *), void *data);
|
||||
void (*unregister_framedone_handler)(enum omap_channel channel,
|
||||
void (*handler)(void *), void *data);
|
||||
};
|
||||
|
||||
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops);
|
||||
void dss_uninstall_mgr_ops(void);
|
||||
|
||||
int dss_mgr_connect(enum omap_channel channel,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_disconnect(enum omap_channel channel,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_set_timings(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings);
|
||||
void dss_mgr_set_lcd_config(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
int dss_mgr_enable(enum omap_channel channel);
|
||||
void dss_mgr_disable(enum omap_channel channel);
|
||||
void dss_mgr_start_update(enum omap_channel channel);
|
||||
int dss_mgr_register_framedone_handler(enum omap_channel channel,
|
||||
void (*handler)(void *), void *data);
|
||||
void dss_mgr_unregister_framedone_handler(enum omap_channel channel,
|
||||
void (*handler)(void *), void *data);
|
||||
|
||||
#endif /* __OMAP_DRM_DSS_H */
|
|
@ -169,24 +169,6 @@ struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_find_output_from_display);
|
||||
|
||||
struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out;
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
out = omapdss_find_output_from_display(dssdev);
|
||||
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
mgr = out->manager;
|
||||
|
||||
omap_dss_put_device(out);
|
||||
|
||||
return mgr;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_find_mgr_from_display);
|
||||
|
||||
static const struct dss_mgr_ops *dss_mgr_ops;
|
||||
|
||||
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops)
|
||||
|
@ -206,62 +188,62 @@ void dss_uninstall_mgr_ops(void)
|
|||
}
|
||||
EXPORT_SYMBOL(dss_uninstall_mgr_ops);
|
||||
|
||||
int dss_mgr_connect(struct omap_overlay_manager *mgr,
|
||||
int dss_mgr_connect(enum omap_channel channel,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
return dss_mgr_ops->connect(mgr, dst);
|
||||
return dss_mgr_ops->connect(channel, dst);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_connect);
|
||||
|
||||
void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
|
||||
void dss_mgr_disconnect(enum omap_channel channel,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dss_mgr_ops->disconnect(mgr, dst);
|
||||
dss_mgr_ops->disconnect(channel, dst);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_disconnect);
|
||||
|
||||
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
|
||||
void dss_mgr_set_timings(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings)
|
||||
{
|
||||
dss_mgr_ops->set_timings(mgr, timings);
|
||||
dss_mgr_ops->set_timings(channel, timings);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_set_timings);
|
||||
|
||||
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
void dss_mgr_set_lcd_config(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config)
|
||||
{
|
||||
dss_mgr_ops->set_lcd_config(mgr, config);
|
||||
dss_mgr_ops->set_lcd_config(channel, config);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_set_lcd_config);
|
||||
|
||||
int dss_mgr_enable(struct omap_overlay_manager *mgr)
|
||||
int dss_mgr_enable(enum omap_channel channel)
|
||||
{
|
||||
return dss_mgr_ops->enable(mgr);
|
||||
return dss_mgr_ops->enable(channel);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_enable);
|
||||
|
||||
void dss_mgr_disable(struct omap_overlay_manager *mgr)
|
||||
void dss_mgr_disable(enum omap_channel channel)
|
||||
{
|
||||
dss_mgr_ops->disable(mgr);
|
||||
dss_mgr_ops->disable(channel);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_disable);
|
||||
|
||||
void dss_mgr_start_update(struct omap_overlay_manager *mgr)
|
||||
void dss_mgr_start_update(enum omap_channel channel)
|
||||
{
|
||||
dss_mgr_ops->start_update(mgr);
|
||||
dss_mgr_ops->start_update(channel);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_start_update);
|
||||
|
||||
int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
int dss_mgr_register_framedone_handler(enum omap_channel channel,
|
||||
void (*handler)(void *), void *data)
|
||||
{
|
||||
return dss_mgr_ops->register_framedone_handler(mgr, handler, data);
|
||||
return dss_mgr_ops->register_framedone_handler(channel, handler, data);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
|
||||
|
||||
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void dss_mgr_unregister_framedone_handler(enum omap_channel channel,
|
||||
void (*handler)(void *), void *data)
|
||||
{
|
||||
dss_mgr_ops->unregister_framedone_handler(mgr, handler, data);
|
||||
dss_mgr_ops->unregister_framedone_handler(channel, handler, data);
|
||||
}
|
||||
EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);
|
||||
|
|
|
@ -1,456 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "OVERLAY"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
|
||||
}
|
||||
|
||||
static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
ovl->manager ? ovl->manager->name : "<none>");
|
||||
}
|
||||
|
||||
static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int i, r;
|
||||
struct omap_overlay_manager *mgr = NULL;
|
||||
struct omap_overlay_manager *old_mgr;
|
||||
int len = size;
|
||||
|
||||
if (buf[size-1] == '\n')
|
||||
--len;
|
||||
|
||||
if (len > 0) {
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
|
||||
if (sysfs_streq(buf, mgr->name))
|
||||
break;
|
||||
|
||||
mgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (len > 0 && mgr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (mgr)
|
||||
DSSDBG("manager %s found\n", mgr->name);
|
||||
|
||||
if (mgr == ovl->manager)
|
||||
return size;
|
||||
|
||||
old_mgr = ovl->manager;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* detach old manager */
|
||||
if (old_mgr) {
|
||||
r = ovl->unset_manager(ovl);
|
||||
if (r) {
|
||||
DSSERR("detach failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = old_mgr->apply(old_mgr);
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mgr) {
|
||||
r = ovl->set_manager(ovl, mgr);
|
||||
if (r) {
|
||||
DSSERR("Failed to attach overlay\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return size;
|
||||
|
||||
err:
|
||||
dispc_runtime_put();
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
info.width, info.height);
|
||||
}
|
||||
|
||||
static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
|
||||
}
|
||||
|
||||
static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
info.pos_x, info.pos_y);
|
||||
}
|
||||
|
||||
static ssize_t overlay_position_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
char *last;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.pos_x = simple_strtoul(buf, &last, 10);
|
||||
++last;
|
||||
if (last - buf >= size)
|
||||
return -EINVAL;
|
||||
|
||||
info.pos_y = simple_strtoul(last, &last, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
info.out_width, info.out_height);
|
||||
}
|
||||
|
||||
static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
char *last;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.out_width = simple_strtoul(buf, &last, 10);
|
||||
++last;
|
||||
if (last - buf >= size)
|
||||
return -EINVAL;
|
||||
|
||||
info.out_height = simple_strtoul(last, &last, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
|
||||
}
|
||||
|
||||
static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int r;
|
||||
bool enable;
|
||||
|
||||
r = strtobool(buf, &enable);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (enable)
|
||||
r = ovl->enable(ovl);
|
||||
else
|
||||
r = ovl->disable(ovl);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
info.global_alpha);
|
||||
}
|
||||
|
||||
static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
u8 alpha;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
r = kstrtou8(buf, 0, &alpha);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.global_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_pre_mult_alpha_show(struct omap_overlay *ovl,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
info.pre_mult_alpha);
|
||||
}
|
||||
|
||||
static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", 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)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct overlay_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct omap_overlay *, char *);
|
||||
ssize_t (*store)(struct omap_overlay *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define OVERLAY_ATTR(_name, _mode, _show, _store) \
|
||||
struct overlay_attribute overlay_attr_##_name = \
|
||||
__ATTR(_name, _mode, _show, _store)
|
||||
|
||||
static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
|
||||
static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
|
||||
overlay_manager_show, overlay_manager_store);
|
||||
static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
|
||||
static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
|
||||
static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
|
||||
overlay_position_show, overlay_position_store);
|
||||
static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
|
||||
overlay_output_size_show, overlay_output_size_store);
|
||||
static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
overlay_enabled_show, overlay_enabled_store);
|
||||
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
|
||||
overlay_global_alpha_show, overlay_global_alpha_store);
|
||||
static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
|
||||
overlay_pre_mult_alpha_show,
|
||||
overlay_pre_mult_alpha_store);
|
||||
static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
|
||||
overlay_zorder_show, overlay_zorder_store);
|
||||
|
||||
static struct attribute *overlay_sysfs_attrs[] = {
|
||||
&overlay_attr_name.attr,
|
||||
&overlay_attr_manager.attr,
|
||||
&overlay_attr_input_size.attr,
|
||||
&overlay_attr_screen_width.attr,
|
||||
&overlay_attr_position.attr,
|
||||
&overlay_attr_output_size.attr,
|
||||
&overlay_attr_enabled.attr,
|
||||
&overlay_attr_global_alpha.attr,
|
||||
&overlay_attr_pre_mult_alpha.attr,
|
||||
&overlay_attr_zorder.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay *overlay;
|
||||
struct overlay_attribute *overlay_attr;
|
||||
|
||||
overlay = container_of(kobj, struct omap_overlay, kobj);
|
||||
overlay_attr = container_of(attr, struct overlay_attribute, attr);
|
||||
|
||||
if (!overlay_attr->show)
|
||||
return -ENOENT;
|
||||
|
||||
return overlay_attr->show(overlay, buf);
|
||||
}
|
||||
|
||||
static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay *overlay;
|
||||
struct overlay_attribute *overlay_attr;
|
||||
|
||||
overlay = container_of(kobj, struct omap_overlay, kobj);
|
||||
overlay_attr = container_of(attr, struct overlay_attribute, attr);
|
||||
|
||||
if (!overlay_attr->store)
|
||||
return -ENOENT;
|
||||
|
||||
return overlay_attr->store(overlay, buf, size);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops overlay_sysfs_ops = {
|
||||
.show = overlay_attr_show,
|
||||
.store = overlay_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type overlay_ktype = {
|
||||
.sysfs_ops = &overlay_sysfs_ops,
|
||||
.default_attrs = overlay_sysfs_attrs,
|
||||
};
|
||||
|
||||
int dss_overlay_kobj_init(struct omap_overlay *ovl,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
|
||||
&pdev->dev.kobj, "overlay%d", ovl->id);
|
||||
}
|
||||
|
||||
void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
|
||||
{
|
||||
kobject_del(&ovl->kobj);
|
||||
kobject_put(&ovl->kobj);
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
* linux/drivers/video/omap2/dss/overlay.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "OVERLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static int num_overlays;
|
||||
static struct omap_overlay *overlays;
|
||||
|
||||
int omap_dss_get_num_overlays(void)
|
||||
{
|
||||
return num_overlays;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_num_overlays);
|
||||
|
||||
struct omap_overlay *omap_dss_get_overlay(int num)
|
||||
{
|
||||
if (num >= num_overlays)
|
||||
return NULL;
|
||||
|
||||
return &overlays[num];
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_overlay);
|
||||
|
||||
void dss_init_overlays(struct platform_device *pdev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
num_overlays = dss_feat_get_num_ovls();
|
||||
|
||||
overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
|
||||
GFP_KERNEL);
|
||||
|
||||
BUG_ON(overlays == NULL);
|
||||
|
||||
for (i = 0; i < num_overlays; ++i) {
|
||||
struct omap_overlay *ovl = &overlays[i];
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
ovl->name = "gfx";
|
||||
ovl->id = OMAP_DSS_GFX;
|
||||
break;
|
||||
case 1:
|
||||
ovl->name = "vid1";
|
||||
ovl->id = OMAP_DSS_VIDEO1;
|
||||
break;
|
||||
case 2:
|
||||
ovl->name = "vid2";
|
||||
ovl->id = OMAP_DSS_VIDEO2;
|
||||
break;
|
||||
case 3:
|
||||
ovl->name = "vid3";
|
||||
ovl->id = OMAP_DSS_VIDEO3;
|
||||
break;
|
||||
}
|
||||
|
||||
ovl->caps = dss_feat_get_overlay_caps(ovl->id);
|
||||
ovl->supported_modes =
|
||||
dss_feat_get_supported_color_modes(ovl->id);
|
||||
|
||||
r = dss_overlay_kobj_init(ovl, pdev);
|
||||
if (r)
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
}
|
||||
}
|
||||
|
||||
void dss_uninit_overlays(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_overlays; ++i) {
|
||||
struct omap_overlay *ovl = &overlays[i];
|
||||
dss_overlay_kobj_uninit(ovl);
|
||||
}
|
||||
|
||||
kfree(overlays);
|
||||
overlays = NULL;
|
||||
num_overlays = 0;
|
||||
}
|
||||
|
||||
int dss_ovl_simple_check(struct omap_overlay *ovl,
|
||||
const struct omap_overlay_info *info)
|
||||
{
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
|
||||
if (info->out_width != 0 && info->width != info->out_width) {
|
||||
DSSERR("check_overlay: overlay %d doesn't support "
|
||||
"scaling\n", ovl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->out_height != 0 && info->height != info->out_height) {
|
||||
DSSERR("check_overlay: overlay %d doesn't support "
|
||||
"scaling\n", ovl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ovl->supported_modes & info->color_mode) == 0) {
|
||||
DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
|
||||
ovl->id, info->color_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->zorder >= omap_dss_get_num_overlays()) {
|
||||
DSSERR("check_overlay: zorder %d too high\n", info->zorder);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
|
||||
DSSERR("check_overlay: rotation type %d not supported\n",
|
||||
info->rotation_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
|
||||
const struct omap_video_timings *mgr_timings)
|
||||
{
|
||||
u16 outw, outh;
|
||||
u16 dw, dh;
|
||||
|
||||
dw = mgr_timings->x_res;
|
||||
dh = mgr_timings->y_res;
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
|
||||
outw = info->width;
|
||||
outh = info->height;
|
||||
} else {
|
||||
if (info->out_width == 0)
|
||||
outw = info->width;
|
||||
else
|
||||
outw = info->out_width;
|
||||
|
||||
if (info->out_height == 0)
|
||||
outh = info->height;
|
||||
else
|
||||
outh = info->out_height;
|
||||
}
|
||||
|
||||
if (dw < info->pos_x + outw) {
|
||||
DSSERR("overlay %d horizontally not inside the display area "
|
||||
"(%d + %d >= %d)\n",
|
||||
ovl->id, info->pos_x, outw, dw);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dh < info->pos_y + outh) {
|
||||
DSSERR("overlay %d vertically not inside the display area "
|
||||
"(%d + %d >= %d)\n",
|
||||
ovl->id, info->pos_y, outh, dh);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if replication logic should be used. Only use when overlay is in
|
||||
* RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp
|
||||
*/
|
||||
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
|
||||
enum omap_color_mode mode)
|
||||
{
|
||||
if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
|
||||
return false;
|
||||
|
||||
return config.video_port_width > 16;
|
||||
}
|
|
@ -880,7 +880,7 @@ static int rfbi_display_enable(struct omap_dss_device *dssdev)
|
|||
struct omap_dss_device *out = &rfbi.output;
|
||||
int r;
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ static int sdi_calc_clock_div(unsigned long pclk,
|
|||
|
||||
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
|
||||
|
||||
|
@ -124,19 +124,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
|
|||
sdi.mgr_config.video_port_width = 24;
|
||||
sdi.mgr_config.lcden_sig_polarity = 1;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
|
||||
dss_mgr_set_lcd_config(channel, &sdi.mgr_config);
|
||||
}
|
||||
|
||||
static int sdi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &sdi.output;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
struct omap_video_timings *t = &sdi.timings;
|
||||
unsigned long fck;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
unsigned long pck;
|
||||
int r;
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -169,7 +170,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
}
|
||||
|
||||
|
||||
dss_mgr_set_timings(out->manager, t);
|
||||
dss_mgr_set_timings(channel, t);
|
||||
|
||||
r = dss_set_fck_rate(fck);
|
||||
if (r)
|
||||
|
@ -188,7 +189,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
* need to care about the shadow register mechanism for pck-free. The
|
||||
* exact reason for this is unknown.
|
||||
*/
|
||||
dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
|
||||
dispc_mgr_set_clock_div(channel, &sdi.mgr_config.clock_info);
|
||||
|
||||
dss_sdi_init(sdi.datapairs);
|
||||
r = dss_sdi_enable();
|
||||
|
@ -196,7 +197,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
goto err_sdi_enable;
|
||||
mdelay(2);
|
||||
|
||||
r = dss_mgr_enable(out->manager);
|
||||
r = dss_mgr_enable(channel);
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
|
@ -216,9 +217,9 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
static void sdi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
dss_mgr_disable(channel);
|
||||
|
||||
dss_sdi_disable();
|
||||
|
||||
|
@ -242,9 +243,9 @@ static void sdi_get_timings(struct omap_dss_device *dssdev,
|
|||
static int sdi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = sdi.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
|
||||
if (!dispc_mgr_timings_ok(channel, timings))
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->pixelclock == 0)
|
||||
|
@ -280,18 +281,14 @@ static int sdi_init_regulator(void)
|
|||
static int sdi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
int r;
|
||||
|
||||
r = sdi_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
r = dss_mgr_connect(channel, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -299,7 +296,7 @@ static int sdi_connect(struct omap_dss_device *dssdev,
|
|||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -309,6 +306,8 @@ static int sdi_connect(struct omap_dss_device *dssdev,
|
|||
static void sdi_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
|
@ -316,8 +315,7 @@ static void sdi_disconnect(struct omap_dss_device *dssdev,
|
|||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_sdi_ops sdi_ops = {
|
||||
|
|
|
@ -443,7 +443,7 @@ static const struct venc_config *venc_timings_to_config(
|
|||
|
||||
static int venc_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = venc.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
u32 l;
|
||||
int r;
|
||||
|
||||
|
@ -469,13 +469,13 @@ static int venc_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, l);
|
||||
|
||||
dss_mgr_set_timings(mgr, &venc.timings);
|
||||
dss_mgr_set_timings(channel, &venc.timings);
|
||||
|
||||
r = regulator_enable(venc.vdda_dac_reg);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
r = dss_mgr_enable(mgr);
|
||||
r = dss_mgr_enable(channel);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
|
@ -494,12 +494,12 @@ static int venc_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
static void venc_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_manager *mgr = venc.output.manager;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
|
||||
dss_set_dac_pwrdn_bgz(0);
|
||||
|
||||
dss_mgr_disable(mgr);
|
||||
dss_mgr_disable(channel);
|
||||
|
||||
regulator_disable(venc.vdda_dac_reg);
|
||||
|
||||
|
@ -515,7 +515,7 @@ static int venc_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
if (out->manager == NULL) {
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("Failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
|
@ -742,18 +742,14 @@ static int venc_get_clocks(struct platform_device *pdev)
|
|||
static int venc_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct omap_overlay_manager *mgr;
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
int r;
|
||||
|
||||
r = venc_init_regulator();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
return -ENODEV;
|
||||
|
||||
r = dss_mgr_connect(mgr, dssdev);
|
||||
r = dss_mgr_connect(channel, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -761,7 +757,7 @@ static int venc_connect(struct omap_dss_device *dssdev,
|
|||
if (r) {
|
||||
DSSERR("failed to connect output to new device: %s\n",
|
||||
dst->name);
|
||||
dss_mgr_disconnect(mgr, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -771,6 +767,8 @@ static int venc_connect(struct omap_dss_device *dssdev,
|
|||
static void venc_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
enum omap_channel channel = dssdev->dispc_channel;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
|
||||
if (dst != dssdev->dst)
|
||||
|
@ -778,8 +776,7 @@ static void venc_disconnect(struct omap_dss_device *dssdev,
|
|||
|
||||
omapdss_output_unset_device(dssdev);
|
||||
|
||||
if (dssdev->manager)
|
||||
dss_mgr_disconnect(dssdev->manager, dssdev);
|
||||
dss_mgr_disconnect(channel, dssdev);
|
||||
}
|
||||
|
||||
static const struct omapdss_atv_ops venc_ops = {
|
||||
|
|
|
@ -63,6 +63,9 @@ void copy_timings_omap_to_drm(struct drm_display_mode *mode,
|
|||
if (timings->interlace)
|
||||
mode->flags |= DRM_MODE_FLAG_INTERLACE;
|
||||
|
||||
if (timings->double_pixel)
|
||||
mode->flags |= DRM_MODE_FLAG_DBLCLK;
|
||||
|
||||
if (timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
|
||||
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
else
|
||||
|
@ -90,6 +93,7 @@ void copy_timings_drm_to_omap(struct omap_video_timings *timings,
|
|||
timings->vbp = mode->vtotal - mode->vsync_end;
|
||||
|
||||
timings->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
||||
timings->double_pixel = !!(mode->flags & DRM_MODE_FLAG_DBLCLK);
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
timings->hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
|
||||
|
|
|
@ -34,14 +34,6 @@ struct omap_crtc {
|
|||
const char *name;
|
||||
enum omap_channel channel;
|
||||
|
||||
/*
|
||||
* Temporary: eventually this will go away, but it is needed
|
||||
* for now to keep the output's happy. (They only need
|
||||
* mgr->id.) Eventually this will be replaced w/ something
|
||||
* more common-panel-framework-y
|
||||
*/
|
||||
struct omap_overlay_manager *mgr;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
|
||||
struct omap_drm_irq vblank_irq;
|
||||
|
@ -80,9 +72,13 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
|
|||
{
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
|
||||
/*
|
||||
* Timeout is set to a "sufficiently" high value, which should cover
|
||||
* a single frame refresh even on slower displays.
|
||||
*/
|
||||
return wait_event_timeout(omap_crtc->pending_wait,
|
||||
!omap_crtc->pending,
|
||||
msecs_to_jiffies(50));
|
||||
msecs_to_jiffies(250));
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -100,31 +96,32 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
|
|||
|
||||
/* ovl-mgr-id -> crtc */
|
||||
static struct omap_crtc *omap_crtcs[8];
|
||||
static struct omap_dss_device *omap_crtc_output[8];
|
||||
|
||||
/* we can probably ignore these until we support command-mode panels: */
|
||||
static int omap_crtc_dss_connect(struct omap_overlay_manager *mgr,
|
||||
static int omap_crtc_dss_connect(enum omap_channel channel,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
if (mgr->output)
|
||||
if (omap_crtc_output[channel])
|
||||
return -EINVAL;
|
||||
|
||||
if ((mgr->supported_outputs & dst->id) == 0)
|
||||
if ((dispc_mgr_get_supported_outputs(channel) & dst->id) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
dst->manager = mgr;
|
||||
mgr->output = dst;
|
||||
omap_crtc_output[channel] = dst;
|
||||
dst->dispc_channel_connected = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_crtc_dss_disconnect(struct omap_overlay_manager *mgr,
|
||||
static void omap_crtc_dss_disconnect(enum omap_channel channel,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
mgr->output->manager = NULL;
|
||||
mgr->output = NULL;
|
||||
omap_crtc_output[channel] = NULL;
|
||||
dst->dispc_channel_connected = false;
|
||||
}
|
||||
|
||||
static void omap_crtc_dss_start_update(struct omap_overlay_manager *mgr)
|
||||
static void omap_crtc_dss_start_update(enum omap_channel channel)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -138,6 +135,11 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
|
|||
u32 framedone_irq, vsync_irq;
|
||||
int ret;
|
||||
|
||||
if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
dispc_mgr_enable(channel, enable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispc_mgr_is_enabled(channel) == enable)
|
||||
return;
|
||||
|
||||
|
@ -186,9 +188,9 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
|
|||
}
|
||||
|
||||
|
||||
static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr)
|
||||
static int omap_crtc_dss_enable(enum omap_channel channel)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[channel];
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
@ -205,38 +207,38 @@ static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void omap_crtc_dss_disable(struct omap_overlay_manager *mgr)
|
||||
static void omap_crtc_dss_disable(enum omap_channel channel)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[channel];
|
||||
|
||||
omap_crtc_set_enabled(&omap_crtc->base, false);
|
||||
}
|
||||
|
||||
static void omap_crtc_dss_set_timings(struct omap_overlay_manager *mgr,
|
||||
static void omap_crtc_dss_set_timings(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[channel];
|
||||
DBG("%s", omap_crtc->name);
|
||||
omap_crtc->timings = *timings;
|
||||
}
|
||||
|
||||
static void omap_crtc_dss_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
static void omap_crtc_dss_set_lcd_config(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
|
||||
struct omap_crtc *omap_crtc = omap_crtcs[channel];
|
||||
DBG("%s", omap_crtc->name);
|
||||
dispc_mgr_set_lcd_config(omap_crtc->channel, config);
|
||||
}
|
||||
|
||||
static int omap_crtc_dss_register_framedone(
|
||||
struct omap_overlay_manager *mgr,
|
||||
enum omap_channel channel,
|
||||
void (*handler)(void *), void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_crtc_dss_unregister_framedone(
|
||||
struct omap_overlay_manager *mgr,
|
||||
enum omap_channel channel,
|
||||
void (*handler)(void *), void *data)
|
||||
{
|
||||
}
|
||||
|
@ -403,24 +405,40 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
|
|||
}
|
||||
}
|
||||
|
||||
static bool omap_crtc_is_plane_prop(struct drm_device *dev,
|
||||
struct drm_property *property)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
|
||||
return property == priv->zorder_prop ||
|
||||
property == dev->mode_config.rotation_property;
|
||||
}
|
||||
|
||||
static int omap_crtc_atomic_set_property(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
/*
|
||||
* Delegate property set to the primary plane. Get the plane state and
|
||||
* set the property directly.
|
||||
*/
|
||||
if (omap_crtc_is_plane_prop(dev, property)) {
|
||||
struct drm_plane_state *plane_state;
|
||||
struct drm_plane *plane = crtc->primary;
|
||||
|
||||
plane_state = drm_atomic_get_plane_state(state->state, plane);
|
||||
if (!plane_state)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Delegate property set to the primary plane. Get the plane
|
||||
* state and set the property directly.
|
||||
*/
|
||||
|
||||
return drm_atomic_plane_set_property(plane, plane_state, property, val);
|
||||
plane_state = drm_atomic_get_plane_state(state->state, plane);
|
||||
if (IS_ERR(plane_state))
|
||||
return PTR_ERR(plane_state);
|
||||
|
||||
return drm_atomic_plane_set_property(plane, plane_state,
|
||||
property, val);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
|
||||
|
@ -428,14 +446,20 @@ static int omap_crtc_atomic_get_property(struct drm_crtc *crtc,
|
|||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
/*
|
||||
* Delegate property get to the primary plane. The
|
||||
* drm_atomic_plane_get_property() function isn't exported, but can be
|
||||
* called through drm_object_property_get_value() as that will call
|
||||
* drm_atomic_get_property() for atomic drivers.
|
||||
*/
|
||||
return drm_object_property_get_value(&crtc->primary->base, property,
|
||||
val);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
||||
if (omap_crtc_is_plane_prop(dev, property)) {
|
||||
/*
|
||||
* Delegate property get to the primary plane. The
|
||||
* drm_atomic_plane_get_property() function isn't exported, but
|
||||
* can be called through drm_object_property_get_value() as that
|
||||
* will call drm_atomic_get_property() for atomic drivers.
|
||||
*/
|
||||
return drm_object_property_get_value(&crtc->primary->base,
|
||||
property, val);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs omap_crtc_funcs = {
|
||||
|
@ -509,9 +533,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
|||
omap_crtc->error_irq.irq = omap_crtc_error_irq;
|
||||
omap_irq_register(dev, &omap_crtc->error_irq);
|
||||
|
||||
/* temporary: */
|
||||
omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
|
||||
|
||||
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
|
||||
&omap_crtc_funcs, NULL);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -79,6 +79,16 @@ static const uint32_t reg[][4] = {
|
|||
DMM_PAT_DESCR__2, DMM_PAT_DESCR__3},
|
||||
};
|
||||
|
||||
static u32 dmm_read(struct dmm *dmm, u32 reg)
|
||||
{
|
||||
return readl(dmm->base + reg);
|
||||
}
|
||||
|
||||
static void dmm_write(struct dmm *dmm, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, dmm->base + reg);
|
||||
}
|
||||
|
||||
/* simple allocator to grab next 16 byte aligned memory from txn */
|
||||
static void *alloc_dma(struct dmm_txn *txn, size_t sz, dma_addr_t *pa)
|
||||
{
|
||||
|
@ -108,7 +118,7 @@ static int wait_status(struct refill_engine *engine, uint32_t wait_mask)
|
|||
|
||||
i = DMM_FIXED_RETRY_COUNT;
|
||||
while (true) {
|
||||
r = readl(dmm->base + reg[PAT_STATUS][engine->id]);
|
||||
r = dmm_read(dmm, reg[PAT_STATUS][engine->id]);
|
||||
err = r & DMM_PATSTATUS_ERR;
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
@ -140,11 +150,11 @@ static void release_engine(struct refill_engine *engine)
|
|||
static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct dmm *dmm = arg;
|
||||
uint32_t status = readl(dmm->base + DMM_PAT_IRQSTATUS);
|
||||
uint32_t status = dmm_read(dmm, DMM_PAT_IRQSTATUS);
|
||||
int i;
|
||||
|
||||
/* ack IRQ */
|
||||
writel(status, dmm->base + DMM_PAT_IRQSTATUS);
|
||||
dmm_write(dmm, status, DMM_PAT_IRQSTATUS);
|
||||
|
||||
for (i = 0; i < dmm->num_engines; i++) {
|
||||
if (status & DMM_IRQSTAT_LST) {
|
||||
|
@ -264,7 +274,7 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
|
|||
txn->last_pat->next_pa = 0;
|
||||
|
||||
/* write to PAT_DESCR to clear out any pending transaction */
|
||||
writel(0x0, dmm->base + reg[PAT_DESCR][engine->id]);
|
||||
dmm_write(dmm, 0x0, reg[PAT_DESCR][engine->id]);
|
||||
|
||||
/* wait for engine ready: */
|
||||
ret = wait_status(engine, DMM_PATSTATUS_READY);
|
||||
|
@ -280,8 +290,7 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait)
|
|||
smp_mb();
|
||||
|
||||
/* kick reload */
|
||||
writel(engine->refill_pa,
|
||||
dmm->base + reg[PAT_DESCR][engine->id]);
|
||||
dmm_write(dmm, engine->refill_pa, reg[PAT_DESCR][engine->id]);
|
||||
|
||||
if (wait) {
|
||||
if (!wait_for_completion_timeout(&engine->compl,
|
||||
|
@ -309,6 +318,21 @@ static int fill(struct tcm_area *area, struct page **pages,
|
|||
struct tcm_area slice, area_s;
|
||||
struct dmm_txn *txn;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
*
|
||||
* Asynchronous fill does not work reliably, as the driver does not
|
||||
* handle errors in the async code paths. The fill operation may
|
||||
* silently fail, leading to leaking DMM engines, which may eventually
|
||||
* lead to deadlock if we run out of DMM engines.
|
||||
*
|
||||
* For now, always set 'wait' so that we only use sync fills. Async
|
||||
* fills should be fixed, or alternatively we could decide to only
|
||||
* support sync fills and so the whole async code path could be removed.
|
||||
*/
|
||||
|
||||
wait = true;
|
||||
|
||||
txn = dmm_txn_init(omap_dmm, area->tcm);
|
||||
if (IS_ERR_OR_NULL(txn))
|
||||
return -ENOMEM;
|
||||
|
@ -642,7 +666,7 @@ static int omap_dmm_probe(struct platform_device *dev)
|
|||
|
||||
omap_dmm->dev = &dev->dev;
|
||||
|
||||
hwinfo = readl(omap_dmm->base + DMM_PAT_HWINFO);
|
||||
hwinfo = dmm_read(omap_dmm, DMM_PAT_HWINFO);
|
||||
omap_dmm->num_engines = (hwinfo >> 24) & 0x1F;
|
||||
omap_dmm->num_lut = (hwinfo >> 16) & 0x1F;
|
||||
omap_dmm->container_width = 256;
|
||||
|
@ -651,7 +675,7 @@ static int omap_dmm_probe(struct platform_device *dev)
|
|||
atomic_set(&omap_dmm->engine_counter, omap_dmm->num_engines);
|
||||
|
||||
/* read out actual LUT width and height */
|
||||
pat_geom = readl(omap_dmm->base + DMM_PAT_GEOMETRY);
|
||||
pat_geom = dmm_read(omap_dmm, DMM_PAT_GEOMETRY);
|
||||
omap_dmm->lut_width = ((pat_geom >> 16) & 0xF) << 5;
|
||||
omap_dmm->lut_height = ((pat_geom >> 24) & 0xF) << 5;
|
||||
|
||||
|
@ -661,12 +685,12 @@ static int omap_dmm_probe(struct platform_device *dev)
|
|||
omap_dmm->num_lut++;
|
||||
|
||||
/* initialize DMM registers */
|
||||
writel(0x88888888, omap_dmm->base + DMM_PAT_VIEW__0);
|
||||
writel(0x88888888, omap_dmm->base + DMM_PAT_VIEW__1);
|
||||
writel(0x80808080, omap_dmm->base + DMM_PAT_VIEW_MAP__0);
|
||||
writel(0x80000000, omap_dmm->base + DMM_PAT_VIEW_MAP_BASE);
|
||||
writel(0x88888888, omap_dmm->base + DMM_TILER_OR__0);
|
||||
writel(0x88888888, omap_dmm->base + DMM_TILER_OR__1);
|
||||
dmm_write(omap_dmm, 0x88888888, DMM_PAT_VIEW__0);
|
||||
dmm_write(omap_dmm, 0x88888888, DMM_PAT_VIEW__1);
|
||||
dmm_write(omap_dmm, 0x80808080, DMM_PAT_VIEW_MAP__0);
|
||||
dmm_write(omap_dmm, 0x80000000, DMM_PAT_VIEW_MAP_BASE);
|
||||
dmm_write(omap_dmm, 0x88888888, DMM_TILER_OR__0);
|
||||
dmm_write(omap_dmm, 0x88888888, DMM_TILER_OR__1);
|
||||
|
||||
ret = request_irq(omap_dmm->irq, omap_dmm_irq_handler, IRQF_SHARED,
|
||||
"omap_dmm_irq_handler", omap_dmm);
|
||||
|
@ -684,7 +708,7 @@ static int omap_dmm_probe(struct platform_device *dev)
|
|||
* buffers for accelerated pan/scroll) and FILL_DSC<n> which
|
||||
* we just generally don't care about.
|
||||
*/
|
||||
writel(0x7e7e7e7e, omap_dmm->base + DMM_PAT_IRQENABLE_SET);
|
||||
dmm_write(omap_dmm, 0x7e7e7e7e, DMM_PAT_IRQENABLE_SET);
|
||||
|
||||
omap_dmm->dummy_page = alloc_page(GFP_KERNEL | __GFP_DMA32);
|
||||
if (!omap_dmm->dummy_page) {
|
||||
|
|
|
@ -340,7 +340,7 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
enum omap_channel channel;
|
||||
struct omap_overlay_manager *mgr;
|
||||
struct omap_dss_device *out;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
continue;
|
||||
|
@ -387,8 +387,10 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
* not considered.
|
||||
*/
|
||||
|
||||
mgr = omapdss_find_mgr_from_display(dssdev);
|
||||
channel = mgr->id;
|
||||
out = omapdss_find_output_from_display(dssdev);
|
||||
channel = out->dispc_channel;
|
||||
omap_dss_put_device(out);
|
||||
|
||||
/*
|
||||
* if this channel hasn't already been taken by a previously
|
||||
* allocated crtc, we create a new crtc for it
|
||||
|
@ -858,12 +860,52 @@ static int pdev_remove(struct platform_device *device)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int omap_drm_suspend_all_displays(void)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
dssdev->driver->disable(dssdev);
|
||||
dssdev->activate_after_resume = true;
|
||||
} else {
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_drm_resume_all_displays(void)
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
for_each_dss_dev(dssdev) {
|
||||
if (!dssdev->driver)
|
||||
continue;
|
||||
|
||||
if (dssdev->activate_after_resume) {
|
||||
dssdev->driver->enable(dssdev);
|
||||
dssdev->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_drm_suspend(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
drm_kms_helper_poll_disable(drm_dev);
|
||||
|
||||
drm_modeset_lock_all(drm_dev);
|
||||
omap_drm_suspend_all_displays();
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -871,6 +913,10 @@ static int omap_drm_resume(struct device *dev)
|
|||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
drm_modeset_lock_all(drm_dev);
|
||||
omap_drm_resume_all_displays();
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
|
||||
drm_kms_helper_poll_enable(drm_dev);
|
||||
|
||||
return omap_gem_resume(dev);
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include <drm/drm_gem.h>
|
||||
#include <drm/omap_drm.h>
|
||||
|
||||
#include "dss/omapdss.h"
|
||||
|
||||
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */
|
||||
|
||||
|
@ -188,12 +190,15 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
|
|||
struct omap_drm_window *win, struct omap_overlay_info *info);
|
||||
struct drm_connector *omap_framebuffer_get_next_connector(
|
||||
struct drm_framebuffer *fb, struct drm_connector *from);
|
||||
bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb);
|
||||
|
||||
void omap_gem_init(struct drm_device *dev);
|
||||
void omap_gem_deinit(struct drm_device *dev);
|
||||
|
||||
struct drm_gem_object *omap_gem_new(struct drm_device *dev,
|
||||
union omap_gem_size gsize, uint32_t flags);
|
||||
struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size,
|
||||
struct sg_table *sgt);
|
||||
int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
||||
union omap_gem_size gsize, uint32_t flags, uint32_t *handle);
|
||||
void omap_gem_free_object(struct drm_gem_object *obj);
|
||||
|
|
|
@ -139,11 +139,16 @@ static void omap_encoder_enable(struct drm_encoder *encoder)
|
|||
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
|
||||
struct omap_dss_device *dssdev = omap_encoder->dssdev;
|
||||
struct omap_dss_driver *dssdrv = dssdev->driver;
|
||||
int r;
|
||||
|
||||
omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc),
|
||||
omap_crtc_timings(encoder->crtc));
|
||||
|
||||
dssdrv->enable(dssdev);
|
||||
r = dssdrv->enable(dssdev);
|
||||
if (r)
|
||||
dev_err(encoder->dev->dev,
|
||||
"Failed to enable display '%s': %d\n",
|
||||
dssdev->name, r);
|
||||
}
|
||||
|
||||
static int omap_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
|
|
|
@ -145,6 +145,14 @@ static uint32_t get_linear_addr(struct plane *plane,
|
|||
return plane->paddr + offset;
|
||||
}
|
||||
|
||||
bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb)
|
||||
{
|
||||
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
|
||||
struct plane *plane = &omap_fb->planes[0];
|
||||
|
||||
return omap_gem_flags(plane->bo) & OMAP_BO_TILED;
|
||||
}
|
||||
|
||||
/* update ovl info for scanout, handles cases of multi-planar fb's, etc.
|
||||
*/
|
||||
void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
|
||||
|
@ -449,6 +457,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (i > 0 && pitch != mode_cmd->pitches[i - 1]) {
|
||||
dev_err(dev->dev,
|
||||
"pitches are not the same between framebuffer planes %d != %d\n",
|
||||
pitch, mode_cmd->pitches[i - 1]);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
plane->bo = bos[i];
|
||||
plane->offset = mode_cmd->offsets[i];
|
||||
plane->pitch = pitch;
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
*/
|
||||
|
||||
/* note: we use upper 8 bits of flags for driver-internal flags: */
|
||||
#define OMAP_BO_DMA 0x01000000 /* actually is physically contiguous */
|
||||
#define OMAP_BO_EXT_SYNC 0x02000000 /* externally allocated sync object */
|
||||
#define OMAP_BO_EXT_MEM 0x04000000 /* externally allocated memory */
|
||||
#define OMAP_BO_MEM_DMA_API 0x01000000 /* memory allocated with the dma_alloc_* API */
|
||||
#define OMAP_BO_MEM_SHMEM 0x02000000 /* memory allocated through shmem backing */
|
||||
#define OMAP_BO_MEM_DMABUF 0x08000000 /* memory imported from a dmabuf */
|
||||
|
||||
struct omap_gem_object {
|
||||
struct drm_gem_object base;
|
||||
|
@ -49,17 +49,25 @@ struct omap_gem_object {
|
|||
uint32_t roll;
|
||||
|
||||
/**
|
||||
* If buffer is allocated physically contiguous, the OMAP_BO_DMA flag
|
||||
* is set and the paddr is valid. Also if the buffer is remapped in
|
||||
* TILER and paddr_cnt > 0, then paddr is valid. But if you are using
|
||||
* the physical address and OMAP_BO_DMA is not set, then you should
|
||||
* be going thru omap_gem_{get,put}_paddr() to ensure the mapping is
|
||||
* not removed from under your feet.
|
||||
* paddr contains the buffer DMA address. It is valid for
|
||||
*
|
||||
* Note that OMAP_BO_SCANOUT is a hint from userspace that DMA capable
|
||||
* buffer is requested, but doesn't mean that it is. Use the
|
||||
* OMAP_BO_DMA flag to determine if the buffer has a DMA capable
|
||||
* physical address.
|
||||
* - buffers allocated through the DMA mapping API (with the
|
||||
* OMAP_BO_MEM_DMA_API flag set)
|
||||
*
|
||||
* - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set)
|
||||
* if they are physically contiguous (when sgt->orig_nents == 1)
|
||||
*
|
||||
* - buffers mapped through the TILER when paddr_cnt is not zero, in
|
||||
* which case the DMA address points to the TILER aperture
|
||||
*
|
||||
* Physically contiguous buffers have their DMA address equal to the
|
||||
* physical address as we don't remap those buffers through the TILER.
|
||||
*
|
||||
* Buffers mapped to the TILER have their DMA address pointing to the
|
||||
* TILER aperture. As TILER mappings are refcounted (through paddr_cnt)
|
||||
* the DMA address must be accessed through omap_get_get_paddr() to
|
||||
* ensure that the mapping won't disappear unexpectedly. References must
|
||||
* be released with omap_gem_put_paddr().
|
||||
*/
|
||||
dma_addr_t paddr;
|
||||
|
||||
|
@ -68,6 +76,12 @@ struct omap_gem_object {
|
|||
*/
|
||||
uint32_t paddr_cnt;
|
||||
|
||||
/**
|
||||
* If the buffer has been imported from a dmabuf the OMAP_DB_DMABUF flag
|
||||
* is set and the sgt field is valid.
|
||||
*/
|
||||
struct sg_table *sgt;
|
||||
|
||||
/**
|
||||
* tiler block used when buffer is remapped in DMM/TILER.
|
||||
*/
|
||||
|
@ -91,17 +105,7 @@ struct omap_gem_object {
|
|||
* sync-object allocated on demand (if needed)
|
||||
*
|
||||
* Per-buffer sync-object for tracking pending and completed hw/dma
|
||||
* read and write operations. The layout in memory is dictated by
|
||||
* the SGX firmware, which uses this information to stall the command
|
||||
* stream if a surface is not ready yet.
|
||||
*
|
||||
* Note that when buffer is used by SGX, the sync-object needs to be
|
||||
* allocated from a special heap of sync-objects. This way many sync
|
||||
* objects can be packed in a page, and not waste GPU virtual address
|
||||
* space. Because of this we have to have a omap_gem_set_sync_object()
|
||||
* API to allow replacement of the syncobj after it has (potentially)
|
||||
* already been allocated. A bit ugly but I haven't thought of a
|
||||
* better alternative.
|
||||
* read and write operations.
|
||||
*/
|
||||
struct {
|
||||
uint32_t write_pending;
|
||||
|
@ -166,16 +170,15 @@ static uint64_t mmap_offset(struct drm_gem_object *obj)
|
|||
return drm_vma_node_offset_addr(&obj->vma_node);
|
||||
}
|
||||
|
||||
/* GEM objects can either be allocated from contiguous memory (in which
|
||||
* case obj->filp==NULL), or w/ shmem backing (obj->filp!=NULL). But non
|
||||
* contiguous buffers can be remapped in TILER/DMM if they need to be
|
||||
* contiguous... but we don't do this all the time to reduce pressure
|
||||
* on TILER/DMM space when we know at allocation time that the buffer
|
||||
* will need to be scanned out.
|
||||
*/
|
||||
static inline bool is_shmem(struct drm_gem_object *obj)
|
||||
static bool is_contiguous(struct omap_gem_object *omap_obj)
|
||||
{
|
||||
return obj->filp != NULL;
|
||||
if (omap_obj->flags & OMAP_BO_MEM_DMA_API)
|
||||
return true;
|
||||
|
||||
if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -264,6 +267,19 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj)
|
|||
for (i = 0; i < npages; i++) {
|
||||
addrs[i] = dma_map_page(dev->dev, pages[i],
|
||||
0, PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
|
||||
if (dma_mapping_error(dev->dev, addrs[i])) {
|
||||
dev_warn(dev->dev,
|
||||
"%s: failed to map page\n", __func__);
|
||||
|
||||
for (i = i - 1; i >= 0; --i) {
|
||||
dma_unmap_page(dev->dev, addrs[i],
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
goto free_addrs;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addrs = kzalloc(npages * sizeof(*addrs), GFP_KERNEL);
|
||||
|
@ -278,6 +294,8 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj)
|
|||
|
||||
return 0;
|
||||
|
||||
free_addrs:
|
||||
kfree(addrs);
|
||||
free_pages:
|
||||
drm_gem_put_pages(obj, pages, true, false);
|
||||
|
||||
|
@ -292,7 +310,7 @@ static int get_pages(struct drm_gem_object *obj, struct page ***pages)
|
|||
struct omap_gem_object *omap_obj = to_omap_bo(obj);
|
||||
int ret = 0;
|
||||
|
||||
if (is_shmem(obj) && !omap_obj->pages) {
|
||||
if ((omap_obj->flags & OMAP_BO_MEM_SHMEM) && !omap_obj->pages) {
|
||||
ret = omap_gem_attach_pages(obj);
|
||||
if (ret) {
|
||||
dev_err(obj->dev->dev, "could not attach pages\n");
|
||||
|
@ -396,7 +414,7 @@ static int fault_1d(struct drm_gem_object *obj,
|
|||
omap_gem_cpu_sync(obj, pgoff);
|
||||
pfn = page_to_pfn(omap_obj->pages[pgoff]);
|
||||
} else {
|
||||
BUG_ON(!(omap_obj->flags & OMAP_BO_DMA));
|
||||
BUG_ON(!is_contiguous(omap_obj));
|
||||
pfn = (omap_obj->paddr >> PAGE_SHIFT) + pgoff;
|
||||
}
|
||||
|
||||
|
@ -560,6 +578,11 @@ int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
case 0:
|
||||
case -ERESTARTSYS:
|
||||
case -EINTR:
|
||||
case -EBUSY:
|
||||
/*
|
||||
* EBUSY is ok: this just means that another thread
|
||||
* already did the job.
|
||||
*/
|
||||
return VM_FAULT_NOPAGE;
|
||||
case -ENOMEM:
|
||||
return VM_FAULT_OOM;
|
||||
|
@ -728,7 +751,8 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll)
|
|||
static inline bool is_cached_coherent(struct drm_gem_object *obj)
|
||||
{
|
||||
struct omap_gem_object *omap_obj = to_omap_bo(obj);
|
||||
return is_shmem(obj) &&
|
||||
|
||||
return (omap_obj->flags & OMAP_BO_MEM_SHMEM) &&
|
||||
((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED);
|
||||
}
|
||||
|
||||
|
@ -761,9 +785,20 @@ void omap_gem_dma_sync(struct drm_gem_object *obj,
|
|||
|
||||
for (i = 0; i < npages; i++) {
|
||||
if (!omap_obj->addrs[i]) {
|
||||
omap_obj->addrs[i] = dma_map_page(dev->dev, pages[i], 0,
|
||||
dma_addr_t addr;
|
||||
|
||||
addr = dma_map_page(dev->dev, pages[i], 0,
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
|
||||
if (dma_mapping_error(dev->dev, addr)) {
|
||||
dev_warn(dev->dev,
|
||||
"%s: failed to map page\n",
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
omap_obj->addrs[i] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,7 +822,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj,
|
|||
|
||||
mutex_lock(&obj->dev->struct_mutex);
|
||||
|
||||
if (remap && is_shmem(obj) && priv->has_dmm) {
|
||||
if (!is_contiguous(omap_obj) && remap && priv->has_dmm) {
|
||||
if (omap_obj->paddr_cnt == 0) {
|
||||
struct page **pages;
|
||||
uint32_t npages = obj->size >> PAGE_SHIFT;
|
||||
|
@ -834,7 +869,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj,
|
|||
omap_obj->paddr_cnt++;
|
||||
|
||||
*paddr = omap_obj->paddr;
|
||||
} else if (omap_obj->flags & OMAP_BO_DMA) {
|
||||
} else if (is_contiguous(omap_obj)) {
|
||||
*paddr = omap_obj->paddr;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
|
@ -1138,20 +1173,6 @@ static inline int sync_op(struct drm_gem_object *obj,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* it is a bit lame to handle updates in this sort of polling way, but
|
||||
* in case of PVR, the GPU can directly update read/write complete
|
||||
* values, and not really tell us which ones it updated.. this also
|
||||
* means that sync_lock is not quite sufficient. So we'll need to
|
||||
* do something a bit better when it comes time to add support for
|
||||
* separate 2d hw..
|
||||
*/
|
||||
void omap_gem_op_update(void)
|
||||
{
|
||||
spin_lock(&sync_lock);
|
||||
sync_op_update();
|
||||
spin_unlock(&sync_lock);
|
||||
}
|
||||
|
||||
/* mark the start of read and/or write operation */
|
||||
int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op)
|
||||
{
|
||||
|
@ -1219,7 +1240,7 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op)
|
|||
* is currently blocked.. fxn() can be called from any context
|
||||
*
|
||||
* (TODO for now fxn is called back from whichever context calls
|
||||
* omap_gem_op_update().. but this could be better defined later
|
||||
* omap_gem_op_finish().. but this could be better defined later
|
||||
* if needed)
|
||||
*
|
||||
* TODO more code in common w/ _sync()..
|
||||
|
@ -1261,50 +1282,10 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* special API so PVR can update the buffer to use a sync-object allocated
|
||||
* from it's sync-obj heap. Only used for a newly allocated (from PVR's
|
||||
* perspective) sync-object, so we overwrite the new syncobj w/ values
|
||||
* from the already allocated syncobj (if there is one)
|
||||
*/
|
||||
int omap_gem_set_sync_object(struct drm_gem_object *obj, void *syncobj)
|
||||
{
|
||||
struct omap_gem_object *omap_obj = to_omap_bo(obj);
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&sync_lock);
|
||||
|
||||
if ((omap_obj->flags & OMAP_BO_EXT_SYNC) && !syncobj) {
|
||||
/* clearing a previously set syncobj */
|
||||
syncobj = kmemdup(omap_obj->sync, sizeof(*omap_obj->sync),
|
||||
GFP_ATOMIC);
|
||||
if (!syncobj) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
omap_obj->flags &= ~OMAP_BO_EXT_SYNC;
|
||||
omap_obj->sync = syncobj;
|
||||
} else if (syncobj && !(omap_obj->flags & OMAP_BO_EXT_SYNC)) {
|
||||
/* replacing an existing syncobj */
|
||||
if (omap_obj->sync) {
|
||||
memcpy(syncobj, omap_obj->sync, sizeof(*omap_obj->sync));
|
||||
kfree(omap_obj->sync);
|
||||
}
|
||||
omap_obj->flags |= OMAP_BO_EXT_SYNC;
|
||||
omap_obj->sync = syncobj;
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock(&sync_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Constructor & Destructor
|
||||
*/
|
||||
|
||||
/* don't call directly.. called from GEM core when it is time to actually
|
||||
* free the object..
|
||||
*/
|
||||
void omap_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
@ -1324,22 +1305,23 @@ void omap_gem_free_object(struct drm_gem_object *obj)
|
|||
*/
|
||||
WARN_ON(omap_obj->paddr_cnt > 0);
|
||||
|
||||
/* don't free externally allocated backing memory */
|
||||
if (!(omap_obj->flags & OMAP_BO_EXT_MEM)) {
|
||||
if (omap_obj->pages)
|
||||
if (omap_obj->pages) {
|
||||
if (omap_obj->flags & OMAP_BO_MEM_DMABUF)
|
||||
kfree(omap_obj->pages);
|
||||
else
|
||||
omap_gem_detach_pages(obj);
|
||||
|
||||
if (!is_shmem(obj)) {
|
||||
dma_free_writecombine(dev->dev, obj->size,
|
||||
omap_obj->vaddr, omap_obj->paddr);
|
||||
} else if (omap_obj->vaddr) {
|
||||
vunmap(omap_obj->vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
/* don't free externally allocated syncobj */
|
||||
if (!(omap_obj->flags & OMAP_BO_EXT_SYNC))
|
||||
kfree(omap_obj->sync);
|
||||
if (omap_obj->flags & OMAP_BO_MEM_DMA_API) {
|
||||
dma_free_writecombine(dev->dev, obj->size,
|
||||
omap_obj->vaddr, omap_obj->paddr);
|
||||
} else if (omap_obj->vaddr) {
|
||||
vunmap(omap_obj->vaddr);
|
||||
} else if (obj->import_attach) {
|
||||
drm_prime_gem_destroy(obj, omap_obj->sgt);
|
||||
}
|
||||
|
||||
kfree(omap_obj->sync);
|
||||
|
||||
drm_gem_object_release(obj);
|
||||
|
||||
|
@ -1357,84 +1339,160 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,
|
|||
size_t size;
|
||||
int ret;
|
||||
|
||||
/* Validate the flags and compute the memory and cache flags. */
|
||||
if (flags & OMAP_BO_TILED) {
|
||||
if (!priv->usergart) {
|
||||
dev_err(dev->dev, "Tiled buffers require DMM\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* tiled buffers are always shmem paged backed.. when they are
|
||||
* scanned out, they are remapped into DMM/TILER
|
||||
/*
|
||||
* Tiled buffers are always shmem paged backed. When they are
|
||||
* scanned out, they are remapped into DMM/TILER.
|
||||
*/
|
||||
flags &= ~OMAP_BO_SCANOUT;
|
||||
flags |= OMAP_BO_MEM_SHMEM;
|
||||
|
||||
/* currently don't allow cached buffers.. there is some caching
|
||||
* stuff that needs to be handled better
|
||||
/*
|
||||
* Currently don't allow cached buffers. There is some caching
|
||||
* stuff that needs to be handled better.
|
||||
*/
|
||||
flags &= ~(OMAP_BO_CACHED|OMAP_BO_WC|OMAP_BO_UNCACHED);
|
||||
flags |= tiler_get_cpu_cache_flags();
|
||||
|
||||
/* align dimensions to slot boundaries... */
|
||||
tiler_align(gem2fmt(flags),
|
||||
&gsize.tiled.width, &gsize.tiled.height);
|
||||
|
||||
/* ...and calculate size based on aligned dimensions */
|
||||
size = tiler_size(gem2fmt(flags),
|
||||
gsize.tiled.width, gsize.tiled.height);
|
||||
} else {
|
||||
size = PAGE_ALIGN(gsize.bytes);
|
||||
} else if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) {
|
||||
/*
|
||||
* OMAP_BO_SCANOUT hints that the buffer doesn't need to be
|
||||
* tiled. However, to lower the pressure on memory allocation,
|
||||
* use contiguous memory only if no TILER is available.
|
||||
*/
|
||||
flags |= OMAP_BO_MEM_DMA_API;
|
||||
} else if (!(flags & OMAP_BO_MEM_DMABUF)) {
|
||||
/*
|
||||
* All other buffers not backed by dma_buf are shmem-backed.
|
||||
*/
|
||||
flags |= OMAP_BO_MEM_SHMEM;
|
||||
}
|
||||
|
||||
/* Allocate the initialize the OMAP GEM object. */
|
||||
omap_obj = kzalloc(sizeof(*omap_obj), GFP_KERNEL);
|
||||
if (!omap_obj)
|
||||
return NULL;
|
||||
|
||||
obj = &omap_obj->base;
|
||||
omap_obj->flags = flags;
|
||||
|
||||
if ((flags & OMAP_BO_SCANOUT) && !priv->has_dmm) {
|
||||
/* attempt to allocate contiguous memory if we don't
|
||||
* have DMM for remappign discontiguous buffers
|
||||
if (flags & OMAP_BO_TILED) {
|
||||
/*
|
||||
* For tiled buffers align dimensions to slot boundaries and
|
||||
* calculate size based on aligned dimensions.
|
||||
*/
|
||||
omap_obj->vaddr = dma_alloc_writecombine(dev->dev, size,
|
||||
&omap_obj->paddr, GFP_KERNEL);
|
||||
if (!omap_obj->vaddr) {
|
||||
kfree(omap_obj);
|
||||
tiler_align(gem2fmt(flags), &gsize.tiled.width,
|
||||
&gsize.tiled.height);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
size = tiler_size(gem2fmt(flags), gsize.tiled.width,
|
||||
gsize.tiled.height);
|
||||
|
||||
flags |= OMAP_BO_DMA;
|
||||
omap_obj->width = gsize.tiled.width;
|
||||
omap_obj->height = gsize.tiled.height;
|
||||
} else {
|
||||
size = PAGE_ALIGN(gsize.bytes);
|
||||
}
|
||||
|
||||
/* Initialize the GEM object. */
|
||||
if (!(flags & OMAP_BO_MEM_SHMEM)) {
|
||||
drm_gem_private_object_init(dev, obj, size);
|
||||
} else {
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
mapping = file_inode(obj->filp)->i_mapping;
|
||||
mapping_set_gfp_mask(mapping, GFP_USER | __GFP_DMA32);
|
||||
}
|
||||
|
||||
/* Allocate memory if needed. */
|
||||
if (flags & OMAP_BO_MEM_DMA_API) {
|
||||
omap_obj->vaddr = dma_alloc_writecombine(dev->dev, size,
|
||||
&omap_obj->paddr,
|
||||
GFP_KERNEL);
|
||||
if (!omap_obj->vaddr)
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
spin_lock(&priv->list_lock);
|
||||
list_add(&omap_obj->mm_list, &priv->obj_list);
|
||||
spin_unlock(&priv->list_lock);
|
||||
|
||||
omap_obj->flags = flags;
|
||||
|
||||
if (flags & OMAP_BO_TILED) {
|
||||
omap_obj->width = gsize.tiled.width;
|
||||
omap_obj->height = gsize.tiled.height;
|
||||
}
|
||||
|
||||
if (flags & (OMAP_BO_DMA|OMAP_BO_EXT_MEM)) {
|
||||
drm_gem_private_object_init(dev, obj, size);
|
||||
} else {
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
mapping = file_inode(obj->filp)->i_mapping;
|
||||
mapping_set_gfp_mask(mapping, GFP_USER | __GFP_DMA32);
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
fail:
|
||||
omap_gem_free_object(obj);
|
||||
err_release:
|
||||
drm_gem_object_release(obj);
|
||||
err_free:
|
||||
kfree(omap_obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size,
|
||||
struct sg_table *sgt)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
struct omap_gem_object *omap_obj;
|
||||
struct drm_gem_object *obj;
|
||||
union omap_gem_size gsize;
|
||||
|
||||
/* Without a DMM only physically contiguous buffers can be supported. */
|
||||
if (sgt->orig_nents != 1 && !priv->has_dmm)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
gsize.bytes = PAGE_ALIGN(size);
|
||||
obj = omap_gem_new(dev, gsize, OMAP_BO_MEM_DMABUF | OMAP_BO_WC);
|
||||
if (!obj) {
|
||||
obj = ERR_PTR(-ENOMEM);
|
||||
goto done;
|
||||
}
|
||||
|
||||
omap_obj = to_omap_bo(obj);
|
||||
omap_obj->sgt = sgt;
|
||||
|
||||
if (sgt->orig_nents == 1) {
|
||||
omap_obj->paddr = sg_dma_address(sgt->sgl);
|
||||
} else {
|
||||
/* Create pages list from sgt */
|
||||
struct sg_page_iter iter;
|
||||
struct page **pages;
|
||||
unsigned int npages;
|
||||
unsigned int i = 0;
|
||||
|
||||
npages = DIV_ROUND_UP(size, PAGE_SIZE);
|
||||
pages = kcalloc(npages, sizeof(*pages), GFP_KERNEL);
|
||||
if (!pages) {
|
||||
omap_gem_free_object(obj);
|
||||
obj = ERR_PTR(-ENOMEM);
|
||||
goto done;
|
||||
}
|
||||
|
||||
omap_obj->pages = pages;
|
||||
|
||||
for_each_sg_page(sgt->sgl, &iter, sgt->orig_nents, 0) {
|
||||
pages[i++] = sg_page_iter_page(&iter);
|
||||
if (i > npages)
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN_ON(i != npages)) {
|
||||
omap_gem_free_object(obj);
|
||||
obj = ERR_PTR(-ENOMEM);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* convenience method to construct a GEM buffer object, and userspace handle */
|
||||
int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,
|
||||
union omap_gem_size gsize, uint32_t flags, uint32_t *handle)
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
|
||||
#include "omap_drv.h"
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* DMABUF Export
|
||||
*/
|
||||
|
||||
static struct sg_table *omap_gem_map_dma_buf(
|
||||
struct dma_buf_attachment *attachment,
|
||||
enum dma_data_direction dir)
|
||||
|
@ -178,15 +182,20 @@ struct dma_buf *omap_gem_prime_export(struct drm_device *dev,
|
|||
return dma_buf_export(&exp_info);
|
||||
}
|
||||
|
||||
struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf *buffer)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
/* -----------------------------------------------------------------------------
|
||||
* DMABUF Import
|
||||
*/
|
||||
|
||||
/* is this one of own objects? */
|
||||
if (buffer->ops == &omap_dmabuf_ops) {
|
||||
obj = buffer->priv;
|
||||
/* is it from our device? */
|
||||
struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
|
||||
struct dma_buf *dma_buf)
|
||||
{
|
||||
struct dma_buf_attachment *attach;
|
||||
struct drm_gem_object *obj;
|
||||
struct sg_table *sgt;
|
||||
int ret;
|
||||
|
||||
if (dma_buf->ops == &omap_dmabuf_ops) {
|
||||
obj = dma_buf->priv;
|
||||
if (obj->dev == dev) {
|
||||
/*
|
||||
* Importing dmabuf exported from out own gem increases
|
||||
|
@ -197,9 +206,33 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO add support for importing buffers from other devices..
|
||||
* for now we don't need this but would be nice to add eventually
|
||||
*/
|
||||
return ERR_PTR(-EINVAL);
|
||||
attach = dma_buf_attach(dma_buf, dev->dev);
|
||||
if (IS_ERR(attach))
|
||||
return ERR_CAST(attach);
|
||||
|
||||
get_dma_buf(dma_buf);
|
||||
|
||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
goto fail_detach;
|
||||
}
|
||||
|
||||
obj = omap_gem_new_dmabuf(dev, dma_buf->size, sgt);
|
||||
if (IS_ERR(obj)) {
|
||||
ret = PTR_ERR(obj);
|
||||
goto fail_unmap;
|
||||
}
|
||||
|
||||
obj->import_attach = attach;
|
||||
|
||||
return obj;
|
||||
|
||||
fail_unmap:
|
||||
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
|
||||
fail_detach:
|
||||
dma_buf_detach(dma_buf, attach);
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
|
@ -177,6 +177,12 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
|
|||
if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->fb) {
|
||||
if (state->rotation != BIT(DRM_ROTATE_0) &&
|
||||
!omap_framebuffer_supports_rotation(state->fb))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -915,4 +915,5 @@ static inline u16 DISPC_MFLAG_THRESHOLD_OFFSET(enum omap_plane plane)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -412,6 +412,44 @@ void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
|
|||
int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
|
||||
bool mem_to_mem, const struct omap_video_timings *timings);
|
||||
|
||||
u32 dispc_read_irqstatus(void);
|
||||
void dispc_clear_irqstatus(u32 mask);
|
||||
u32 dispc_read_irqenable(void);
|
||||
void dispc_write_irqenable(u32 mask);
|
||||
|
||||
int dispc_request_irq(irq_handler_t handler, void *dev_id);
|
||||
void dispc_free_irq(void *dev_id);
|
||||
|
||||
int dispc_runtime_get(void);
|
||||
void dispc_runtime_put(void);
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable);
|
||||
bool dispc_mgr_is_enabled(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel);
|
||||
bool dispc_mgr_go_busy(enum omap_channel channel);
|
||||
void dispc_mgr_go(enum omap_channel channel);
|
||||
void dispc_mgr_set_lcd_config(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
void dispc_mgr_set_timings(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings);
|
||||
void dispc_mgr_setup(enum omap_channel channel,
|
||||
const struct omap_overlay_manager_info *info);
|
||||
|
||||
int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
|
||||
const struct omap_overlay_info *oi,
|
||||
const struct omap_video_timings *timings,
|
||||
int *x_predecim, int *y_predecim);
|
||||
|
||||
int dispc_ovl_enable(enum omap_plane plane, bool enable);
|
||||
bool dispc_ovl_enabled(enum omap_plane plane);
|
||||
void dispc_ovl_set_channel_out(enum omap_plane plane,
|
||||
enum omap_channel channel);
|
||||
int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
|
||||
bool replication, const struct omap_video_timings *mgr_timings,
|
||||
bool mem_to_mem);
|
||||
|
||||
/* VENC */
|
||||
int venc_init_platform_driver(void) __init;
|
||||
void venc_uninit_platform_driver(void);
|
||||
|
@ -465,4 +503,44 @@ int dss_pll_write_config_type_b(struct dss_pll *pll,
|
|||
const struct dss_pll_clock_info *cinfo);
|
||||
int dss_pll_wait_reset_done(struct dss_pll *pll);
|
||||
|
||||
/* compat */
|
||||
|
||||
struct dss_mgr_ops {
|
||||
int (*connect)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
void (*start_update)(struct omap_overlay_manager *mgr);
|
||||
int (*enable)(struct omap_overlay_manager *mgr);
|
||||
void (*disable)(struct omap_overlay_manager *mgr);
|
||||
void (*set_timings)(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings);
|
||||
void (*set_lcd_config)(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
int (*register_framedone_handler)(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
void (*unregister_framedone_handler)(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
};
|
||||
|
||||
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops);
|
||||
void dss_uninstall_mgr_ops(void);
|
||||
|
||||
int dss_mgr_connect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings);
|
||||
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
int dss_mgr_enable(struct omap_overlay_manager *mgr);
|
||||
void dss_mgr_disable(struct omap_overlay_manager *mgr);
|
||||
void dss_mgr_start_update(struct omap_overlay_manager *mgr);
|
||||
int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,21 +45,6 @@ struct encoder_tfp410_platform_data {
|
|||
int data_lines;
|
||||
};
|
||||
|
||||
/**
|
||||
* encoder_tpd12s015 platform data
|
||||
* @name: name for this display entity
|
||||
* @ct_cp_hpd_gpio: CT_CP_HPD gpio number
|
||||
* @ls_oe_gpio: LS_OE gpio number
|
||||
* @hpd_gpio: HPD gpio number
|
||||
*/
|
||||
struct encoder_tpd12s015_platform_data {
|
||||
const char *name;
|
||||
const char *source;
|
||||
|
||||
int ct_cp_hpd_gpio;
|
||||
int ls_oe_gpio;
|
||||
int hpd_gpio;
|
||||
};
|
||||
|
||||
/**
|
||||
* connector_dvi platform data
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#define DISPC_IRQ_FRAMEDONEWB (1 << 23)
|
||||
#define DISPC_IRQ_FRAMEDONETV (1 << 24)
|
||||
#define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25)
|
||||
#define DISPC_IRQ_WBUNCOMPLETEERROR (1 << 26)
|
||||
#define DISPC_IRQ_SYNC_LOST3 (1 << 27)
|
||||
#define DISPC_IRQ_VSYNC3 (1 << 28)
|
||||
#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29)
|
||||
|
@ -331,8 +332,6 @@ struct omap_dss_board_info {
|
|||
|
||||
/* Init with the board info */
|
||||
extern int omap_display_init(struct omap_dss_board_info *board_data);
|
||||
/* HDMI mux init*/
|
||||
extern int omap_hdmi_init(enum omap_hdmi_flags flags);
|
||||
|
||||
struct omap_video_timings {
|
||||
/* Unit: pixels */
|
||||
|
@ -366,6 +365,8 @@ struct omap_video_timings {
|
|||
enum omap_dss_signal_level de_level;
|
||||
/* Pixel clock edges to drive HSYNC and VSYNC signals */
|
||||
enum omap_dss_signal_edge sync_pclk_edge;
|
||||
|
||||
bool double_pixel;
|
||||
};
|
||||
|
||||
/* Hardcoded timings for tv modes. Venc only uses these to
|
||||
|
@ -769,6 +770,7 @@ struct omap_dss_device {
|
|||
|
||||
/* DISPC channel for this output */
|
||||
enum omap_channel dispc_channel;
|
||||
bool dispc_channel_connected;
|
||||
|
||||
/* output instance */
|
||||
enum omap_dss_output_id id;
|
||||
|
@ -782,13 +784,6 @@ struct omap_dss_device {
|
|||
struct omap_dss_device *dst;
|
||||
};
|
||||
|
||||
struct omap_dss_hdmi_data
|
||||
{
|
||||
int ct_cp_hpd_gpio;
|
||||
int ls_oe_gpio;
|
||||
int hpd_gpio;
|
||||
};
|
||||
|
||||
struct omap_dss_driver {
|
||||
int (*probe)(struct omap_dss_device *);
|
||||
void (*remove)(struct omap_dss_device *);
|
||||
|
@ -897,85 +892,9 @@ typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
|
|||
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
|
||||
int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
|
||||
|
||||
u32 dispc_read_irqstatus(void);
|
||||
void dispc_clear_irqstatus(u32 mask);
|
||||
u32 dispc_read_irqenable(void);
|
||||
void dispc_write_irqenable(u32 mask);
|
||||
|
||||
int dispc_request_irq(irq_handler_t handler, void *dev_id);
|
||||
void dispc_free_irq(void *dev_id);
|
||||
|
||||
int dispc_runtime_get(void);
|
||||
void dispc_runtime_put(void);
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable);
|
||||
bool dispc_mgr_is_enabled(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel);
|
||||
bool dispc_mgr_go_busy(enum omap_channel channel);
|
||||
void dispc_mgr_go(enum omap_channel channel);
|
||||
void dispc_mgr_set_lcd_config(enum omap_channel channel,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
void dispc_mgr_set_timings(enum omap_channel channel,
|
||||
const struct omap_video_timings *timings);
|
||||
void dispc_mgr_setup(enum omap_channel channel,
|
||||
const struct omap_overlay_manager_info *info);
|
||||
|
||||
int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
|
||||
const struct omap_overlay_info *oi,
|
||||
const struct omap_video_timings *timings,
|
||||
int *x_predecim, int *y_predecim);
|
||||
|
||||
int dispc_ovl_enable(enum omap_plane plane, bool enable);
|
||||
bool dispc_ovl_enabled(enum omap_plane plane);
|
||||
void dispc_ovl_set_channel_out(enum omap_plane plane,
|
||||
enum omap_channel channel);
|
||||
int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
|
||||
bool replication, const struct omap_video_timings *mgr_timings,
|
||||
bool mem_to_mem);
|
||||
|
||||
int omapdss_compat_init(void);
|
||||
void omapdss_compat_uninit(void);
|
||||
|
||||
struct dss_mgr_ops {
|
||||
int (*connect)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void (*disconnect)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
void (*start_update)(struct omap_overlay_manager *mgr);
|
||||
int (*enable)(struct omap_overlay_manager *mgr);
|
||||
void (*disable)(struct omap_overlay_manager *mgr);
|
||||
void (*set_timings)(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings);
|
||||
void (*set_lcd_config)(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
int (*register_framedone_handler)(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
void (*unregister_framedone_handler)(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
};
|
||||
|
||||
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops);
|
||||
void dss_uninstall_mgr_ops(void);
|
||||
|
||||
int dss_mgr_connect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dst);
|
||||
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
|
||||
const struct omap_video_timings *timings);
|
||||
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
|
||||
const struct dss_lcd_mgr_config *config);
|
||||
int dss_mgr_enable(struct omap_overlay_manager *mgr);
|
||||
void dss_mgr_disable(struct omap_overlay_manager *mgr);
|
||||
void dss_mgr_start_update(struct omap_overlay_manager *mgr);
|
||||
int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
|
||||
void (*handler)(void *), void *data);
|
||||
|
||||
static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->src;
|
||||
|
|
Loading…
Reference in New Issue