omapdrm changes for v4.20

Big amount of changes from Laurent, reworking the driver towards the
 model used by the other DRM drivers by reverting the direction of many
 of the operations on the display pipeline. The aim of this work is to
 allow omapdrm to use the common DRM panels and bridges.  Not all of the
 operations are dealt in these patches, so more work needs to be done.
 
 The only change visible to the user should be the change in module
 dependencies: e.g. earlier a panel module depended on an encoder module,
 but now the encoder module depends on the panel module, which affects
 the order in which to unload the modules.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEExDgMPpZe/YEHn/On+j2qjLyWHvUFAluNOQoWHHRvbWkudmFs
 a2VpbmVuQHRpLmNvbQAKCRD6PaqMvJYe9av+D/9UBFr0Do+1FrIJ5qePJaZCXTgc
 FolV3q6mRFF/qKlxX82q0utrj1jGZ1uTGJh9D05HCVd7Y5CwNVSs4TtLHi69Bkgz
 3K1LbXSoP6lBwBZYbCnVf7k08ptIqltG6gYR4wklNfqvPBPvtmBXbnFstQgB07VH
 3qBKQr6HxxxSukYZKc57ye5140gH7oWEOw5BnaEcRTpZ7nN3YP2o/ldnxd0CxJ9Q
 fRrbg3vBVdjeRKQOSAvq6SqT3FfdrSl4ohhnb/Y0eIYdB9HnVan2uDd+zFZStbl8
 ojvPDKKDrK8vxcbZHa4V7xySTQgNstChnQSzv0HDgaDcBIzZNlH5DLkwDv4zS4dd
 Bqb7wi55zKn3g+bquORAenU6W+I4WAMeINloyRHN1M35tbyk2qR7NQx8bYXWvMSD
 1IuOMpI+icYokI/x+xlOxL4D86kt8WpLbwJowbDsMMxEmJjYY5eGhZmkUEefZtGl
 L1bw8V7Ydv+1q9pLGZ+NkxmjfOLQj34XeGDzbmxSUYrxc/vMzCo6LzIrOaET6XGI
 1CkbxRwQvdR2PVKKwFf5Kp6sxjmtkZpGp9YZeV4ULSWp9ZfERrqtUA/7ARLY3UGY
 kvFLlSAyoO2/qXrwCnL26Z7nt1fFmsad4QqJ52Sr4Nj9WT13bvkjxZl3oIkHqD5B
 YiGPMjgNqlah4T6Sqw==
 =8425
 -----END PGP SIGNATURE-----

Merge tag 'omapdrm-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next

omapdrm changes for v4.20

Big amount of changes from Laurent, reworking the driver towards the
model used by the other DRM drivers by reverting the direction of many
of the operations on the display pipeline. The aim of this work is to
allow omapdrm to use the common DRM panels and bridges.  Not all of the
operations are dealt in these patches, so more work needs to be done.

The only change visible to the user should be the change in module
dependencies: e.g. earlier a panel module depended on an encoder module,
but now the encoder module depends on the panel module, which affects
the order in which to unload the modules.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/9bb1a01b-a632-ce0c-f249-7b5470967e3a@ti.com
This commit is contained in:
Dave Airlie 2018-09-07 11:03:24 +10:00
commit 1f3eb3461f
42 changed files with 2329 additions and 3907 deletions

View file

@ -18,77 +18,27 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct device *dev;
struct videomode vm;
};
static const struct videomode tvc_pal_vm = {
.hactive = 720,
.vactive = 574,
.pixelclock = 13500000,
.hsync_len = 64,
.hfront_porch = 12,
.hback_porch = 68,
.vsync_len = 5,
.vfront_porch = 5,
.vback_porch = 41,
.flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW |
DISPLAY_FLAGS_VSYNC_LOW,
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int tvc_connect(struct omap_dss_device *dssdev)
static int tvc_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
dev_dbg(ddata->dev, "connect\n");
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node);
if (IS_ERR(in)) {
dev_err(ddata->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.atv->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void tvc_disconnect(struct omap_dss_device *dssdev)
static void tvc_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(ddata->dev, "disconnect\n");
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.atv->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int tvc_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(ddata->dev, "enable\n");
@ -99,9 +49,7 @@ static int tvc_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.atv->set_timings(in, &ddata->vm);
r = in->ops.atv->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -113,83 +61,30 @@ static int tvc_enable(struct omap_dss_device *dssdev)
static void tvc_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
dev_dbg(ddata->dev, "disable\n");
if (!omapdss_device_is_enabled(dssdev))
return;
in->ops.atv->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void tvc_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.atv->set_timings(in, vm);
}
static void tvc_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
*vm = ddata->vm;
}
static int tvc_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.atv->check_timings(in, vm);
}
static u32 tvc_get_wss(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.atv->get_wss(in);
}
static int tvc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.atv->set_wss(in, wss);
}
static struct omap_dss_driver tvc_driver = {
static const struct omap_dss_device_ops tvc_ops = {
.connect = tvc_connect,
.disconnect = tvc_disconnect,
.enable = tvc_enable,
.disable = tvc_disable,
.set_timings = tvc_set_timings,
.get_timings = tvc_get_timings,
.check_timings = tvc_check_timings,
.get_wss = tvc_get_wss,
.set_wss = tvc_set_wss,
};
static int tvc_probe(struct platform_device *pdev)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
int r;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
@ -198,20 +93,15 @@ static int tvc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
ddata->dev = &pdev->dev;
ddata->vm = tvc_pal_vm;
dssdev = &ddata->dssdev;
dssdev->driver = &tvc_driver;
dssdev->ops = &tvc_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = tvc_pal_vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register panel\n");
return r;
}
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -221,10 +111,9 @@ static int __exit tvc_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_display(&ddata->dssdev);
omapdss_device_unregister(&ddata->dssdev);
tvc_disable(dssdev);
tvc_disconnect(dssdev);
return 0;
}

View file

@ -19,30 +19,8 @@
#include "../dss/omapdss.h"
static const struct videomode dvic_default_vm = {
.hactive = 640,
.vactive = 480,
.pixelclock = 23500000,
.hfront_porch = 48,
.hsync_len = 32,
.hback_porch = 80,
.vfront_porch = 3,
.vsync_len = 4,
.vback_porch = 7,
.flags = DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH |
DISPLAY_FLAGS_SYNC_NEGEDGE | DISPLAY_FLAGS_DE_HIGH |
DISPLAY_FLAGS_PIXDATA_POSEDGE,
};
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct videomode vm;
struct i2c_adapter *i2c_adapter;
@ -57,49 +35,20 @@ struct panel_drv_data {
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int dvic_connect(struct omap_dss_device *dssdev)
static int dvic_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dvi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void dvic_disconnect(struct omap_dss_device *dssdev)
static void dvic_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dvi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int dvic_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -108,9 +57,7 @@ static int dvic_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dvi->set_timings(in, &ddata->vm);
r = in->ops.dvi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -121,46 +68,16 @@ static int dvic_enable(struct omap_dss_device *dssdev)
static void dvic_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
in->ops.dvi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void dvic_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dvi->set_timings(in, vm);
}
static void dvic_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
*vm = ddata->vm;
}
static int dvic_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dvi->check_timings(in, vm);
}
static int dvic_ddc_read(struct i2c_adapter *adapter,
unsigned char *buf, u16 count, u8 offset)
{
@ -198,12 +115,6 @@ static int dvic_read_edid(struct omap_dss_device *dssdev,
struct panel_drv_data *ddata = to_panel_data(dssdev);
int r, l, bytes_read;
if (ddata->hpd_gpio && !gpiod_get_value_cansleep(ddata->hpd_gpio))
return -ENODEV;
if (!ddata->i2c_adapter)
return -ENODEV;
l = min(EDID_LENGTH, len);
r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
if (r)
@ -243,78 +154,41 @@ static bool dvic_detect(struct omap_dss_device *dssdev)
return r == 0;
}
static int dvic_register_hpd_cb(struct omap_dss_device *dssdev,
static void dvic_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
if (!ddata->hpd_gpio)
return -ENOTSUPP;
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = cb;
ddata->hpd_cb_data = cb_data;
mutex_unlock(&ddata->hpd_lock);
return 0;
}
static void dvic_unregister_hpd_cb(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
if (!ddata->hpd_gpio)
return;
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = NULL;
ddata->hpd_cb_data = NULL;
mutex_unlock(&ddata->hpd_lock);
}
static void dvic_enable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
if (!ddata->hpd_gpio)
return;
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = true;
mutex_unlock(&ddata->hpd_lock);
}
static void dvic_disable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
if (!ddata->hpd_gpio)
return;
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = false;
mutex_unlock(&ddata->hpd_lock);
}
static struct omap_dss_driver dvic_driver = {
static const struct omap_dss_device_ops dvic_ops = {
.connect = dvic_connect,
.disconnect = dvic_disconnect,
.enable = dvic_enable,
.disable = dvic_disable,
.set_timings = dvic_set_timings,
.get_timings = dvic_get_timings,
.check_timings = dvic_check_timings,
.read_edid = dvic_read_edid,
.detect = dvic_detect,
.register_hpd_cb = dvic_register_hpd_cb,
.unregister_hpd_cb = dvic_unregister_hpd_cb,
.enable_hpd = dvic_enable_hpd,
.disable_hpd = dvic_disable_hpd,
};
static irqreturn_t dvic_hpd_isr(int irq, void *data)
@ -396,28 +270,24 @@ static int dvic_probe(struct platform_device *pdev)
if (r)
return r;
ddata->vm = dvic_default_vm;
dssdev = &ddata->dssdev;
dssdev->driver = &dvic_driver;
dssdev->ops = &dvic_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_DVI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = dvic_default_vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register panel\n");
goto err_reg;
}
if (ddata->hpd_gpio)
dssdev->ops_flags |= OMAP_DSS_DEVICE_OP_DETECT
| OMAP_DSS_DEVICE_OP_HPD;
if (ddata->i2c_adapter)
dssdev->ops_flags |= OMAP_DSS_DEVICE_OP_DETECT
| OMAP_DSS_DEVICE_OP_EDID;
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
err_reg:
i2c_put_adapter(ddata->i2c_adapter);
mutex_destroy(&ddata->hpd_lock);
return r;
}
static int __exit dvic_remove(struct platform_device *pdev)
@ -425,10 +295,9 @@ static int __exit dvic_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_display(&ddata->dssdev);
omapdss_device_unregister(&ddata->dssdev);
dvic_disable(dssdev);
dvic_disconnect(dssdev);
i2c_put_adapter(ddata->i2c_adapter);

View file

@ -10,95 +10,41 @@
*/
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mutex.h>
#include <drm/drm_edid.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "../dss/omapdss.h"
static const struct videomode hdmic_default_vm = {
.hactive = 640,
.vactive = 480,
.pixelclock = 25175000,
.hsync_len = 96,
.hfront_porch = 16,
.hback_porch = 48,
.vsync_len = 2,
.vfront_porch = 11,
.vback_porch = 31,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
void *hpd_cb_data;
bool hpd_enabled;
struct mutex hpd_lock;
struct device *dev;
struct videomode vm;
int hpd_gpio;
struct gpio_desc *hpd_gpio;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int hdmic_connect(struct omap_dss_device *dssdev)
static int hdmic_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
dev_dbg(ddata->dev, "connect\n");
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(ddata->dev->of_node);
if (IS_ERR(in)) {
dev_err(ddata->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.hdmi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void hdmic_disconnect(struct omap_dss_device *dssdev)
static void hdmic_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(ddata->dev, "disconnect\n");
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.hdmi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int hdmic_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(ddata->dev, "enable\n");
@ -109,9 +55,7 @@ static int hdmic_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.hdmi->set_timings(in, &ddata->vm);
r = in->ops.hdmi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -123,171 +67,58 @@ static int hdmic_enable(struct omap_dss_device *dssdev)
static void hdmic_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
dev_dbg(ddata->dev, "disable\n");
if (!omapdss_device_is_enabled(dssdev))
return;
in->ops.hdmi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void hdmic_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.hdmi->set_timings(in, vm);
}
static void hdmic_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
*vm = ddata->vm;
}
static int hdmic_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->check_timings(in, vm);
}
static int hdmic_read_edid(struct omap_dss_device *dssdev,
u8 *edid, int len)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->read_edid(in, edid, len);
}
static bool hdmic_detect(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
bool connected;
if (gpio_is_valid(ddata->hpd_gpio))
connected = gpio_get_value_cansleep(ddata->hpd_gpio);
else
connected = in->ops.hdmi->detect(in);
if (!connected && in->ops.hdmi->lost_hotplug)
in->ops.hdmi->lost_hotplug(in);
return connected;
return gpiod_get_value_cansleep(ddata->hpd_gpio);
}
static int hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
static void hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data)
void *cb_data)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = cb;
ddata->hpd_cb_data = cb_data;
mutex_unlock(&ddata->hpd_lock);
return 0;
} else if (in->ops.hdmi->register_hpd_cb) {
return in->ops.hdmi->register_hpd_cb(in, cb, cb_data);
}
return -ENOTSUPP;
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = cb;
ddata->hpd_cb_data = cb_data;
mutex_unlock(&ddata->hpd_lock);
}
static void hdmic_unregister_hpd_cb(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = NULL;
ddata->hpd_cb_data = NULL;
mutex_unlock(&ddata->hpd_lock);
} else if (in->ops.hdmi->unregister_hpd_cb) {
in->ops.hdmi->unregister_hpd_cb(in);
}
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = NULL;
ddata->hpd_cb_data = NULL;
mutex_unlock(&ddata->hpd_lock);
}
static void hdmic_enable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = true;
mutex_unlock(&ddata->hpd_lock);
} else if (in->ops.hdmi->enable_hpd) {
in->ops.hdmi->enable_hpd(in);
}
}
static void hdmic_disable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = false;
mutex_unlock(&ddata->hpd_lock);
} else if (in->ops.hdmi->disable_hpd) {
in->ops.hdmi->disable_hpd(in);
}
}
static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
}
static int hdmic_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->set_infoframe(in, avi);
}
static struct omap_dss_driver hdmic_driver = {
static const struct omap_dss_device_ops hdmic_ops = {
.connect = hdmic_connect,
.disconnect = hdmic_disconnect,
.enable = hdmic_enable,
.disable = hdmic_disable,
.set_timings = hdmic_set_timings,
.get_timings = hdmic_get_timings,
.check_timings = hdmic_check_timings,
.read_edid = hdmic_read_edid,
.detect = hdmic_detect,
.register_hpd_cb = hdmic_register_hpd_cb,
.unregister_hpd_cb = hdmic_unregister_hpd_cb,
.enable_hpd = hdmic_enable_hpd,
.disable_hpd = hdmic_disable_hpd,
.set_hdmi_mode = hdmic_set_hdmi_mode,
.set_hdmi_infoframe = hdmic_set_infoframe,
};
static irqreturn_t hdmic_hpd_isr(int irq, void *data)
@ -295,7 +126,7 @@ static irqreturn_t hdmic_hpd_isr(int irq, void *data)
struct panel_drv_data *ddata = data;
mutex_lock(&ddata->hpd_lock);
if (ddata->hpd_enabled && ddata->hpd_cb) {
if (ddata->hpd_cb) {
enum drm_connector_status status;
if (hdmic_detect(&ddata->dssdev))
@ -310,26 +141,11 @@ static irqreturn_t hdmic_hpd_isr(int irq, void *data)
return IRQ_HANDLED;
}
static int hdmic_probe_of(struct platform_device *pdev)
{
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
int gpio;
/* HPD GPIO */
gpio = of_get_named_gpio(node, "hpd-gpios", 0);
if (gpio_is_valid(gpio))
ddata->hpd_gpio = gpio;
else
ddata->hpd_gpio = -ENODEV;
return 0;
}
static int hdmic_probe(struct platform_device *pdev)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
struct gpio_desc *gpio;
int r;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
@ -339,20 +155,20 @@ static int hdmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
ddata->dev = &pdev->dev;
r = hdmic_probe_of(pdev);
if (r)
return r;
mutex_init(&ddata->hpd_lock);
if (gpio_is_valid(ddata->hpd_gpio)) {
r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
GPIOF_DIR_IN, "hdmi_hpd");
if (r)
return r;
/* HPD GPIO */
gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to parse HPD gpio\n");
return PTR_ERR(gpio);
}
ddata->hpd_gpio = gpio;
if (ddata->hpd_gpio) {
r = devm_request_threaded_irq(&pdev->dev,
gpio_to_irq(ddata->hpd_gpio),
gpiod_to_irq(ddata->hpd_gpio),
NULL, hdmic_hpd_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
@ -361,20 +177,18 @@ static int hdmic_probe(struct platform_device *pdev)
return r;
}
ddata->vm = hdmic_default_vm;
dssdev = &ddata->dssdev;
dssdev->driver = &hdmic_driver;
dssdev->ops = &hdmic_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = hdmic_default_vm;
dssdev->of_ports = BIT(0);
dssdev->ops_flags = ddata->hpd_gpio
? OMAP_DSS_DEVICE_OP_DETECT | OMAP_DSS_DEVICE_OP_HPD
: 0;
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register panel\n");
return r;
}
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -384,10 +198,9 @@ static int __exit hdmic_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_display(&ddata->dssdev);
omapdss_device_unregister(&ddata->dssdev);
hdmic_disable(dssdev);
hdmic_disconnect(dssdev);
return 0;
}

View file

@ -23,75 +23,28 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct gpio_desc *enable_gpio;
struct videomode vm;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int opa362_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int opa362_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
dev_dbg(dssdev->dev, "connect\n");
if (omapdss_device_is_connected(dssdev))
return -EBUSY;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.atv->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
dst->src = dssdev;
dssdev->dst = dst;
ddata->in = in;
return 0;
return omapdss_device_connect(dst->dss, dst, dst->next);
}
static void opa362_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void opa362_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "disconnect\n");
WARN_ON(!omapdss_device_is_connected(dssdev));
if (!omapdss_device_is_connected(dssdev))
return;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
dst->src = NULL;
dssdev->dst = NULL;
in->ops.atv->disconnect(in, &ddata->dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
omapdss_device_disconnect(dst, dst->next);
}
static int opa362_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(dssdev->dev, "enable\n");
@ -102,9 +55,7 @@ static int opa362_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.atv->set_timings(in, &ddata->vm);
r = in->ops.atv->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -119,7 +70,7 @@ static int opa362_enable(struct omap_dss_device *dssdev)
static void opa362_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
dev_dbg(dssdev->dev, "disable\n");
@ -129,56 +80,16 @@ static void opa362_disable(struct omap_dss_device *dssdev)
if (ddata->enable_gpio)
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
in->ops.atv->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void opa362_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "set_timings\n");
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.atv->set_timings(in, vm);
}
static void opa362_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
dev_dbg(dssdev->dev, "get_timings\n");
*vm = ddata->vm;
}
static int opa362_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "check_timings\n");
return in->ops.atv->check_timings(in, vm);
}
static const struct omapdss_atv_ops opa362_atv_ops = {
static const struct omap_dss_device_ops opa362_ops = {
.connect = opa362_connect,
.disconnect = opa362_disconnect,
.enable = opa362_enable,
.disable = opa362_disable,
.check_timings = opa362_check_timings,
.set_timings = opa362_set_timings,
.get_timings = opa362_get_timings,
};
static int opa362_probe(struct platform_device *pdev)
@ -186,7 +97,6 @@ static int opa362_probe(struct platform_device *pdev)
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
struct gpio_desc *gpio;
int r;
dev_dbg(&pdev->dev, "probe\n");
@ -203,18 +113,22 @@ static int opa362_probe(struct platform_device *pdev)
ddata->enable_gpio = gpio;
dssdev = &ddata->dssdev;
dssdev->ops.atv = &opa362_atv_ops;
dssdev->ops = &opa362_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
dssdev->owner = THIS_MODULE;
dssdev->of_ports = BIT(1) | BIT(0);
r = omapdss_register_output(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register output\n");
return r;
dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
if (IS_ERR(dssdev->next)) {
if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to find video sink\n");
return PTR_ERR(dssdev->next);
}
omapdss_device_register(dssdev);
return 0;
}
@ -223,7 +137,9 @@ static int __exit opa362_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_output(&ddata->dssdev);
if (dssdev->next)
omapdss_device_put(dssdev->next);
omapdss_device_unregister(&ddata->dssdev);
WARN_ON(omapdss_device_is_enabled(dssdev));
if (omapdss_device_is_enabled(dssdev))
@ -231,7 +147,7 @@ static int __exit opa362_remove(struct platform_device *pdev)
WARN_ON(omapdss_device_is_connected(dssdev));
if (omapdss_device_is_connected(dssdev))
opa362_disconnect(dssdev, dssdev->dst);
omapdss_device_disconnect(NULL, dssdev);
return 0;
}

View file

@ -13,77 +13,33 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include "../dss/omapdss.h"
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
int pd_gpio;
struct videomode vm;
struct gpio_desc *pd_gpio;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int tfp410_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int tfp410_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return -EBUSY;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
dst->src = dssdev;
dssdev->dst = dst;
ddata->in = in;
return 0;
return omapdss_device_connect(dst->dss, dst, dst->next);
}
static void tfp410_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void tfp410_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
WARN_ON(!omapdss_device_is_connected(dssdev));
if (!omapdss_device_is_connected(dssdev))
return;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
dst->src = NULL;
dssdev->dst = NULL;
in->ops.dpi->disconnect(in, &ddata->dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
omapdss_device_disconnect(dst, dst->next);
}
static int tfp410_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -92,14 +48,12 @@ static int tfp410_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
if (gpio_is_valid(ddata->pd_gpio))
gpio_set_value_cansleep(ddata->pd_gpio, 1);
if (ddata->pd_gpio)
gpiod_set_value_cansleep(ddata->pd_gpio, 0);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@ -109,94 +63,31 @@ static int tfp410_enable(struct omap_dss_device *dssdev)
static void tfp410_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
if (gpio_is_valid(ddata->pd_gpio))
gpio_set_value_cansleep(ddata->pd_gpio, 0);
if (ddata->pd_gpio)
gpiod_set_value_cansleep(ddata->pd_gpio, 0);
in->ops.dpi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void tfp410_fix_timings(struct videomode *vm)
{
vm->flags |= DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
DISPLAY_FLAGS_SYNC_POSEDGE;
}
static void tfp410_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
tfp410_fix_timings(vm);
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void tfp410_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
*vm = ddata->vm;
}
static int tfp410_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
tfp410_fix_timings(vm);
return in->ops.dpi->check_timings(in, vm);
}
static const struct omapdss_dvi_ops tfp410_dvi_ops = {
static const struct omap_dss_device_ops tfp410_ops = {
.connect = tfp410_connect,
.disconnect = tfp410_disconnect,
.enable = tfp410_enable,
.disable = tfp410_disable,
.check_timings = tfp410_check_timings,
.set_timings = tfp410_set_timings,
.get_timings = tfp410_get_timings,
};
static int tfp410_probe_of(struct platform_device *pdev)
{
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
int gpio;
gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
if (gpio_is_valid(gpio) || gpio == -ENOENT) {
ddata->pd_gpio = gpio;
} else {
if (gpio != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to parse PD gpio\n");
return gpio;
}
return 0;
}
static int tfp410_probe(struct platform_device *pdev)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
int r;
struct gpio_desc *gpio;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
@ -204,34 +95,34 @@ static int tfp410_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
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,
GPIOF_OUT_INIT_LOW, "tfp410 PD");
if (r) {
dev_err(&pdev->dev, "Failed to request PD GPIO %d\n",
ddata->pd_gpio);
return r;
}
/* Powerdown GPIO */
gpio = devm_gpiod_get_optional(&pdev->dev, "powerdown", GPIOD_OUT_HIGH);
if (IS_ERR(gpio)) {
dev_err(&pdev->dev, "failed to parse powerdown gpio\n");
return PTR_ERR(gpio);
}
ddata->pd_gpio = gpio;
dssdev = &ddata->dssdev;
dssdev->ops.dvi = &tfp410_dvi_ops;
dssdev->ops = &tfp410_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
dssdev->owner = THIS_MODULE;
dssdev->port_num = 1;
dssdev->of_ports = BIT(1) | BIT(0);
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
r = omapdss_register_output(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register output\n");
return r;
dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
if (IS_ERR(dssdev->next)) {
if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to find video sink\n");
return PTR_ERR(dssdev->next);
}
omapdss_device_register(dssdev);
return 0;
}
@ -240,7 +131,9 @@ static int __exit tfp410_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_output(&ddata->dssdev);
if (dssdev->next)
omapdss_device_put(dssdev->next);
omapdss_device_unregister(&ddata->dssdev);
WARN_ON(omapdss_device_is_enabled(dssdev));
if (omapdss_device_is_enabled(dssdev))
@ -248,7 +141,7 @@ static int __exit tfp410_remove(struct platform_device *pdev)
WARN_ON(omapdss_device_is_connected(dssdev));
if (omapdss_device_is_connected(dssdev))
tfp410_disconnect(dssdev, dssdev->dst);
omapdss_device_disconnect(NULL, dssdev);
return 0;
}

View file

@ -21,42 +21,26 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
void *hpd_cb_data;
bool hpd_enabled;
struct mutex hpd_lock;
struct gpio_desc *ct_cp_hpd_gpio;
struct gpio_desc *ls_oe_gpio;
struct gpio_desc *hpd_gpio;
struct videomode vm;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int tpd_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int tpd_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
struct panel_drv_data *ddata = to_panel_data(dst);
int r;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.hdmi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
}
dst->src = dssdev;
dssdev->dst = dst;
gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
gpiod_set_value_cansleep(ddata->ls_oe_gpio, 1);
@ -64,45 +48,29 @@ static int tpd_connect(struct omap_dss_device *dssdev,
/* DC-DC converter needs at max 300us to get to 90% of 5V */
udelay(300);
ddata->in = in;
return 0;
}
static void tpd_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void tpd_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
struct panel_drv_data *ddata = to_panel_data(dst);
gpiod_set_value_cansleep(ddata->ct_cp_hpd_gpio, 0);
gpiod_set_value_cansleep(ddata->ls_oe_gpio, 0);
dst->src = NULL;
dssdev->dst = NULL;
in->ops.hdmi->disconnect(in, &ddata->dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
omapdss_device_disconnect(dst, dst->next);
}
static int tpd_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
in->ops.hdmi->set_timings(in, &ddata->vm);
r = in->ops.hdmi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -113,76 +81,27 @@ static int tpd_enable(struct omap_dss_device *dssdev)
static void tpd_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
in->ops.hdmi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void tpd_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.hdmi->set_timings(in, vm);
}
static void tpd_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
*vm = ddata->vm;
}
static int tpd_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
r = in->ops.hdmi->check_timings(in, vm);
return r;
}
static int tpd_read_edid(struct omap_dss_device *dssdev,
u8 *edid, int len)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!gpiod_get_value_cansleep(ddata->hpd_gpio))
return -ENODEV;
return in->ops.hdmi->read_edid(in, edid, len);
}
static bool tpd_detect(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
bool connected = gpiod_get_value_cansleep(ddata->hpd_gpio);
if (!connected && in->ops.hdmi->lost_hotplug)
in->ops.hdmi->lost_hotplug(in);
return connected;
return gpiod_get_value_cansleep(ddata->hpd_gpio);
}
static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
static void tpd_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data)
void *cb_data)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
@ -190,8 +109,6 @@ static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
ddata->hpd_cb = cb;
ddata->hpd_cb_data = cb_data;
mutex_unlock(&ddata->hpd_lock);
return 0;
}
static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
@ -204,61 +121,14 @@ static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
mutex_unlock(&ddata->hpd_lock);
}
static void tpd_enable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = true;
mutex_unlock(&ddata->hpd_lock);
}
static void tpd_disable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = false;
mutex_unlock(&ddata->hpd_lock);
}
static int tpd_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->set_infoframe(in, avi);
}
static int tpd_set_hdmi_mode(struct omap_dss_device *dssdev,
bool hdmi_mode)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->set_hdmi_mode(in, hdmi_mode);
}
static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
static const struct omap_dss_device_ops tpd_ops = {
.connect = tpd_connect,
.disconnect = tpd_disconnect,
.enable = tpd_enable,
.disable = tpd_disable,
.check_timings = tpd_check_timings,
.set_timings = tpd_set_timings,
.get_timings = tpd_get_timings,
.read_edid = tpd_read_edid,
.detect = tpd_detect,
.register_hpd_cb = tpd_register_hpd_cb,
.unregister_hpd_cb = tpd_unregister_hpd_cb,
.enable_hpd = tpd_enable_hpd,
.disable_hpd = tpd_disable_hpd,
.set_infoframe = tpd_set_infoframe,
.set_hdmi_mode = tpd_set_hdmi_mode,
};
static irqreturn_t tpd_hpd_isr(int irq, void *data)
@ -266,7 +136,7 @@ static irqreturn_t tpd_hpd_isr(int irq, void *data)
struct panel_drv_data *ddata = data;
mutex_lock(&ddata->hpd_lock);
if (ddata->hpd_enabled && ddata->hpd_cb) {
if (ddata->hpd_cb) {
enum drm_connector_status status;
if (tpd_detect(&ddata->dssdev))
@ -283,7 +153,7 @@ static irqreturn_t tpd_hpd_isr(int irq, void *data)
static int tpd_probe(struct platform_device *pdev)
{
struct omap_dss_device *in, *dssdev;
struct omap_dss_device *dssdev;
struct panel_drv_data *ddata;
int r;
struct gpio_desc *gpio;
@ -325,21 +195,24 @@ static int tpd_probe(struct platform_device *pdev)
return r;
dssdev = &ddata->dssdev;
dssdev->ops.hdmi = &tpd_hdmi_ops;
dssdev->ops = &tpd_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->owner = THIS_MODULE;
dssdev->port_num = 1;
dssdev->of_ports = BIT(1) | BIT(0);
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT
| OMAP_DSS_DEVICE_OP_HPD;
in = ddata->in;
r = omapdss_register_output(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register output\n");
return r;
dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
if (IS_ERR(dssdev->next)) {
if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to find video sink\n");
return PTR_ERR(dssdev->next);
}
omapdss_device_register(dssdev);
return 0;
}
@ -348,7 +221,9 @@ static int __exit tpd_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_output(&ddata->dssdev);
if (dssdev->next)
omapdss_device_put(dssdev->next);
omapdss_device_unregister(&ddata->dssdev);
WARN_ON(omapdss_device_is_enabled(dssdev));
if (omapdss_device_is_enabled(dssdev))
@ -356,7 +231,7 @@ static int __exit tpd_remove(struct platform_device *pdev)
WARN_ON(omapdss_device_is_connected(dssdev));
if (omapdss_device_is_connected(dssdev))
tpd_disconnect(dssdev, dssdev->dst);
omapdss_device_disconnect(NULL, dssdev);
return 0;
}

View file

@ -23,7 +23,6 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct videomode vm;
@ -35,49 +34,21 @@ struct panel_drv_data {
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
static int panel_dpi_connect(struct omap_dss_device *dssdev)
static int panel_dpi_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void panel_dpi_disconnect(struct omap_dss_device *dssdev)
static void panel_dpi_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dpi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int panel_dpi_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -86,15 +57,13 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
r = regulator_enable(ddata->vcc_supply);
if (r) {
in->ops.dpi->disable(in);
src->ops->disable(src);
return r;
}
@ -109,7 +78,7 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
static void panel_dpi_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
@ -119,23 +88,11 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
regulator_disable(ddata->vcc_supply);
in->ops.dpi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void panel_dpi_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -144,25 +101,14 @@ static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int panel_dpi_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dpi->check_timings(in, vm);
}
static struct omap_dss_driver panel_dpi_ops = {
static const struct omap_dss_device_ops panel_dpi_ops = {
.connect = panel_dpi_connect,
.disconnect = panel_dpi_disconnect,
.enable = panel_dpi_enable,
.disable = panel_dpi_disable,
.set_timings = panel_dpi_set_timings,
.get_timings = panel_dpi_get_timings,
.check_timings = panel_dpi_check_timings,
};
static int panel_dpi_probe_of(struct platform_device *pdev)
@ -227,16 +173,13 @@ static int panel_dpi_probe(struct platform_device *pdev)
dssdev = &ddata->dssdev;
dssdev->dev = &pdev->dev;
dssdev->driver = &panel_dpi_ops;
dssdev->ops = &panel_dpi_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register panel\n");
return r;
}
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -246,10 +189,9 @@ static int __exit panel_dpi_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
panel_dpi_disable(dssdev);
panel_dpi_disconnect(dssdev);
return 0;
}

View file

@ -41,7 +41,6 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct videomode vm;
@ -142,11 +141,11 @@ static void hw_guard_wait(struct panel_drv_data *ddata)
static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r;
u8 buf[1];
r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd, buf, 1);
r = src->ops->dsi.dcs_read(src, ddata->channel, dcs_cmd, buf, 1);
if (r < 0)
return r;
@ -158,29 +157,30 @@ static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
{
struct omap_dss_device *in = ddata->in;
return in->ops.dsi->dcs_write(in, ddata->channel, &dcs_cmd, 1);
struct omap_dss_device *src = ddata->dssdev.src;
return src->ops->dsi.dcs_write(src, ddata->channel, &dcs_cmd, 1);
}
static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
u8 buf[2] = { dcs_cmd, param };
return in->ops.dsi->dcs_write(in, ddata->channel, buf, 2);
return src->ops->dsi.dcs_write(src, ddata->channel, buf, 2);
}
static int dsicm_sleep_in(struct panel_drv_data *ddata)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
u8 cmd;
int r;
hw_guard_wait(ddata);
cmd = MIPI_DCS_ENTER_SLEEP_MODE;
r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, &cmd, 1);
r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, &cmd, 1);
if (r)
return r;
@ -228,7 +228,7 @@ static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
static int dsicm_set_update_window(struct panel_drv_data *ddata,
u16 x, u16 y, u16 w, u16 h)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r;
u16 x1 = x;
u16 x2 = x + w - 1;
@ -242,7 +242,7 @@ static int dsicm_set_update_window(struct panel_drv_data *ddata,
buf[3] = (x2 >> 8) & 0xff;
buf[4] = (x2 >> 0) & 0xff;
r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, buf, sizeof(buf));
if (r)
return r;
@ -252,11 +252,11 @@ static int dsicm_set_update_window(struct panel_drv_data *ddata,
buf[3] = (y2 >> 8) & 0xff;
buf[4] = (y2 >> 0) & 0xff;
r = in->ops.dsi->dcs_write_nosync(in, ddata->channel, buf, sizeof(buf));
r = src->ops->dsi.dcs_write_nosync(src, ddata->channel, buf, sizeof(buf));
if (r)
return r;
in->ops.dsi->bta_sync(in, ddata->channel);
src->ops->dsi.bta_sync(src, ddata->channel);
return r;
}
@ -275,7 +275,7 @@ static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)
static int dsicm_enter_ulps(struct panel_drv_data *ddata)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r;
if (ddata->ulps_enabled)
@ -290,7 +290,7 @@ static int dsicm_enter_ulps(struct panel_drv_data *ddata)
if (ddata->ext_te_gpio)
disable_irq(gpiod_to_irq(ddata->ext_te_gpio));
in->ops.dsi->disable(in, false, true);
src->ops->dsi.disable(src, false, true);
ddata->ulps_enabled = true;
@ -309,19 +309,19 @@ static int dsicm_enter_ulps(struct panel_drv_data *ddata)
static int dsicm_exit_ulps(struct panel_drv_data *ddata)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r;
if (!ddata->ulps_enabled)
return 0;
r = in->ops.dsi->enable(in);
r = src->ops->enable(src);
if (r) {
dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
goto err1;
}
in->ops.dsi->enable_hs(in, ddata->channel, true);
src->ops->dsi.enable_hs(src, ddata->channel, true);
r = _dsicm_enable_te(ddata, true);
if (r) {
@ -366,7 +366,7 @@ static int dsicm_wake_up(struct panel_drv_data *ddata)
static int dsicm_bl_update_status(struct backlight_device *dev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r = 0;
int level;
@ -381,13 +381,13 @@ static int dsicm_bl_update_status(struct backlight_device *dev)
mutex_lock(&ddata->lock);
if (ddata->enabled) {
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_wake_up(ddata);
if (!r)
r = dsicm_dcs_write_1(ddata, DCS_BRIGHTNESS, level);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
}
mutex_unlock(&ddata->lock);
@ -414,21 +414,21 @@ static ssize_t dsicm_num_errors_show(struct device *dev,
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
u8 errors = 0;
int r;
mutex_lock(&ddata->lock);
if (ddata->enabled) {
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_wake_up(ddata);
if (!r)
r = dsicm_dcs_read_1(ddata, DCS_READ_NUM_ERRORS,
&errors);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
} else {
r = -ENODEV;
}
@ -446,20 +446,20 @@ static ssize_t dsicm_hw_revision_show(struct device *dev,
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
u8 id1, id2, id3;
int r;
mutex_lock(&ddata->lock);
if (ddata->enabled) {
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_wake_up(ddata);
if (!r)
r = dsicm_get_id(ddata, &id1, &id2, &id3);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
} else {
r = -ENODEV;
}
@ -478,7 +478,7 @@ static ssize_t dsicm_store_ulps(struct device *dev,
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
unsigned long t;
int r;
@ -489,14 +489,14 @@ static ssize_t dsicm_store_ulps(struct device *dev,
mutex_lock(&ddata->lock);
if (ddata->enabled) {
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
if (t)
r = dsicm_enter_ulps(ddata);
else
r = dsicm_wake_up(ddata);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
}
mutex_unlock(&ddata->lock);
@ -528,7 +528,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
unsigned long t;
int r;
@ -541,9 +541,9 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
if (ddata->enabled) {
/* dsicm_wake_up will restart the timer */
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_wake_up(ddata);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
}
mutex_unlock(&ddata->lock);
@ -603,7 +603,7 @@ static void dsicm_hw_reset(struct panel_drv_data *ddata)
static int dsicm_power_on(struct panel_drv_data *ddata)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
u8 id1, id2, id3;
int r;
struct omap_dss_dsi_config dsi_config = {
@ -635,7 +635,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
}
if (ddata->pin_config.num_pins > 0) {
r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
r = src->ops->dsi.configure_pins(src, &ddata->pin_config);
if (r) {
dev_err(&ddata->pdev->dev,
"failed to configure DSI pins\n");
@ -643,13 +643,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
}
}
r = in->ops.dsi->set_config(in, &dsi_config);
r = src->ops->dsi.set_config(src, &dsi_config);
if (r) {
dev_err(&ddata->pdev->dev, "failed to configure DSI\n");
goto err_vddi;
}
r = in->ops.dsi->enable(in);
r = src->ops->enable(src);
if (r) {
dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
goto err_vddi;
@ -657,7 +657,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
dsicm_hw_reset(ddata);
in->ops.dsi->enable_hs(in, ddata->channel, false);
src->ops->dsi.enable_hs(src, ddata->channel, false);
r = dsicm_sleep_out(ddata);
if (r)
@ -689,7 +689,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
if (r)
goto err;
r = in->ops.dsi->enable_video_output(in, ddata->channel);
r = src->ops->dsi.enable_video_output(src, ddata->channel);
if (r)
goto err;
@ -701,7 +701,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
ddata->intro_printed = true;
}
in->ops.dsi->enable_hs(in, ddata->channel, true);
src->ops->dsi.enable_hs(src, ddata->channel, true);
return 0;
err:
@ -709,7 +709,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
dsicm_hw_reset(ddata);
in->ops.dsi->disable(in, true, false);
src->ops->dsi.disable(src, true, false);
err_vddi:
if (ddata->vddi)
regulator_disable(ddata->vddi);
@ -722,10 +722,10 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
static void dsicm_power_off(struct panel_drv_data *ddata)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r;
in->ops.dsi->disable_video_output(in, ddata->channel);
src->ops->dsi.disable_video_output(src, ddata->channel);
r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_DISPLAY_OFF);
if (!r)
@ -737,7 +737,7 @@ static void dsicm_power_off(struct panel_drv_data *ddata)
dsicm_hw_reset(ddata);
}
in->ops.dsi->disable(in, true, false);
src->ops->dsi.disable(src, true, false);
if (ddata->vddi)
regulator_disable(ddata->vddi);
@ -756,71 +756,41 @@ static int dsicm_panel_reset(struct panel_drv_data *ddata)
return dsicm_power_on(ddata);
}
static int dsicm_connect(struct omap_dss_device *dssdev)
static int dsicm_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct panel_drv_data *ddata = to_panel_data(dst);
struct device *dev = &ddata->pdev->dev;
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dsi->connect(in, dssdev);
if (r) {
dev_err(dev, "Failed to connect to video source\n");
goto err_connect;
}
r = in->ops.dsi->request_vc(in, &ddata->channel);
r = src->ops->dsi.request_vc(src, &ddata->channel);
if (r) {
dev_err(dev, "failed to get virtual channel\n");
goto err_req_vc;
return r;
}
r = in->ops.dsi->set_vc_id(in, ddata->channel, TCH);
r = src->ops->dsi.set_vc_id(src, ddata->channel, TCH);
if (r) {
dev_err(dev, "failed to set VC_ID\n");
goto err_vc_id;
src->ops->dsi.release_vc(src, ddata->channel);
return r;
}
ddata->in = in;
return 0;
err_vc_id:
in->ops.dsi->release_vc(in, ddata->channel);
err_req_vc:
in->ops.dsi->disconnect(in, dssdev);
err_connect:
omap_dss_put_device(in);
return r;
}
static void dsicm_disconnect(struct omap_dss_device *dssdev)
static void dsicm_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct panel_drv_data *ddata = to_panel_data(dst);
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dsi->release_vc(in, ddata->channel);
in->ops.dsi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
src->ops->dsi.release_vc(src, ddata->channel);
}
static int dsicm_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(&ddata->pdev->dev, "enable\n");
@ -837,11 +807,11 @@ static int dsicm_enable(struct omap_dss_device *dssdev)
goto err;
}
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_power_on(ddata);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
if (r)
goto err;
@ -862,7 +832,7 @@ static int dsicm_enable(struct omap_dss_device *dssdev)
static void dsicm_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(&ddata->pdev->dev, "disable\n");
@ -873,7 +843,7 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
dsicm_cancel_ulps_work(ddata);
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
if (omapdss_device_is_enabled(dssdev)) {
r = dsicm_wake_up(ddata);
@ -881,7 +851,7 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
dsicm_power_off(ddata);
}
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
@ -891,16 +861,16 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
static void dsicm_framedone_cb(int err, void *data)
{
struct panel_drv_data *ddata = data;
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);
in->ops.dsi->bus_unlock(ddata->in);
src->ops->dsi.bus_unlock(src);
}
static irqreturn_t dsicm_te_isr(int irq, void *data)
{
struct panel_drv_data *ddata = data;
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int old;
int r;
@ -909,7 +879,7 @@ static irqreturn_t dsicm_te_isr(int irq, void *data)
if (old) {
cancel_delayed_work(&ddata->te_timeout_work);
r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
r = src->ops->dsi.update(src, ddata->channel, dsicm_framedone_cb,
ddata);
if (r)
goto err;
@ -918,7 +888,7 @@ static irqreturn_t dsicm_te_isr(int irq, void *data)
return IRQ_HANDLED;
err:
dev_err(&ddata->pdev->dev, "start update failed\n");
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
return IRQ_HANDLED;
}
@ -926,25 +896,25 @@ static void dsicm_te_timeout_work_callback(struct work_struct *work)
{
struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
te_timeout_work.work);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");
atomic_set(&ddata->do_update, 0);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
}
static int dsicm_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
mutex_lock(&ddata->lock);
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_wake_up(ddata);
if (r)
@ -956,9 +926,8 @@ static int dsicm_update(struct omap_dss_device *dssdev,
}
/* XXX no need to send this every frame, but dsi break if not done */
r = dsicm_set_update_window(ddata, 0, 0,
dssdev->panel.vm.hactive,
dssdev->panel.vm.vactive);
r = dsicm_set_update_window(ddata, 0, 0, ddata->vm.hactive,
ddata->vm.vactive);
if (r)
goto err;
@ -967,17 +936,17 @@ static int dsicm_update(struct omap_dss_device *dssdev,
msecs_to_jiffies(250));
atomic_set(&ddata->do_update, 1);
} else {
r = in->ops.dsi->update(in, ddata->channel, dsicm_framedone_cb,
r = src->ops->dsi.update(src, ddata->channel, dsicm_framedone_cb,
ddata);
if (r)
goto err;
}
/* note: no bus_unlock here. unlock is in framedone_cb */
/* note: no bus_unlock here. unlock is src framedone_cb */
mutex_unlock(&ddata->lock);
return 0;
err:
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
mutex_unlock(&ddata->lock);
return r;
}
@ -985,13 +954,13 @@ static int dsicm_update(struct omap_dss_device *dssdev,
static int dsicm_sync(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
dev_dbg(&ddata->pdev->dev, "sync\n");
mutex_lock(&ddata->lock);
in->ops.dsi->bus_lock(in);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_lock(src);
src->ops->dsi.bus_unlock(src);
mutex_unlock(&ddata->lock);
dev_dbg(&ddata->pdev->dev, "sync done\n");
@ -1001,7 +970,7 @@ static int dsicm_sync(struct omap_dss_device *dssdev)
static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
{
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = ddata->dssdev.src;
int r;
if (enable)
@ -1010,7 +979,7 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
r = dsicm_dcs_write_0(ddata, MIPI_DCS_SET_TEAR_OFF);
if (!ddata->ext_te_gpio)
in->ops.dsi->enable_te(in, enable);
src->ops->dsi.enable_te(src, enable);
/* possible panel bug */
msleep(100);
@ -1021,7 +990,7 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
mutex_lock(&ddata->lock);
@ -1029,7 +998,7 @@ static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
if (ddata->te_enabled == enable)
goto end;
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
if (ddata->enabled) {
r = dsicm_wake_up(ddata);
@ -1043,13 +1012,13 @@ static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
ddata->te_enabled = enable;
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
end:
mutex_unlock(&ddata->lock);
return 0;
err:
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
mutex_unlock(&ddata->lock);
return r;
@ -1072,7 +1041,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
int first = 1;
int plen;
@ -1089,9 +1058,9 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
}
size = min((u32)w * h * 3,
dssdev->panel.vm.hactive * dssdev->panel.vm.vactive * 3);
ddata->vm.hactive * ddata->vm.vactive * 3);
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
r = dsicm_wake_up(ddata);
if (r)
@ -1107,7 +1076,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
dsicm_set_update_window(ddata, x, y, w, h);
r = in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, plen);
r = src->ops->dsi.set_max_rx_packet_size(src, ddata->channel, plen);
if (r)
goto err2;
@ -1115,7 +1084,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
u8 dcs_cmd = first ? 0x2e : 0x3e;
first = 0;
r = in->ops.dsi->dcs_read(in, ddata->channel, dcs_cmd,
r = src->ops->dsi.dcs_read(src, ddata->channel, dcs_cmd,
buf + buf_used, size - buf_used);
if (r < 0) {
@ -1141,9 +1110,9 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
r = buf_used;
err3:
in->ops.dsi->set_max_rx_packet_size(in, ddata->channel, 1);
src->ops->dsi.set_max_rx_packet_size(src, ddata->channel, 1);
err2:
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
err1:
mutex_unlock(&ddata->lock);
return r;
@ -1154,7 +1123,7 @@ static void dsicm_ulps_work(struct work_struct *work)
struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
ulps_work.work);
struct omap_dss_device *dssdev = &ddata->dssdev;
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
mutex_lock(&ddata->lock);
@ -1163,11 +1132,11 @@ static void dsicm_ulps_work(struct work_struct *work)
return;
}
in->ops.dsi->bus_lock(in);
src->ops->dsi.bus_lock(src);
dsicm_enter_ulps(ddata);
in->ops.dsi->bus_unlock(in);
src->ops->dsi.bus_unlock(src);
mutex_unlock(&ddata->lock);
}
@ -1210,18 +1179,21 @@ static void dsicm_get_size(struct omap_dss_device *dssdev,
*height = ddata->height_mm;
}
static struct omap_dss_driver dsicm_ops = {
static const struct omap_dss_device_ops dsicm_ops = {
.connect = dsicm_connect,
.disconnect = dsicm_disconnect,
.enable = dsicm_enable,
.disable = dsicm_disable,
.get_timings = dsicm_get_timings,
.check_timings = dsicm_check_timings,
};
static const struct omap_dss_driver dsicm_dss_driver = {
.update = dsicm_update,
.sync = dsicm_sync,
.get_timings = dsicm_get_timings,
.check_timings = dsicm_check_timings,
.get_size = dsicm_get_size,
.enable_te = dsicm_enable_te,
@ -1330,20 +1302,17 @@ static int dsicm_probe(struct platform_device *pdev)
dssdev = &ddata->dssdev;
dssdev->dev = dev;
dssdev->driver = &dsicm_ops;
dssdev->panel.vm = ddata->vm;
dssdev->ops = &dsicm_ops;
dssdev->driver = &dsicm_dss_driver;
dssdev->type = OMAP_DISPLAY_TYPE_DSI;
dssdev->owner = THIS_MODULE;
dssdev->of_ports = BIT(0);
dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
r = omapdss_register_display(dssdev);
if (r) {
dev_err(dev, "Failed to register panel\n");
goto err_reg;
}
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
mutex_init(&ddata->lock);
@ -1414,10 +1383,10 @@ static int __exit dsicm_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "remove\n");
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
dsicm_disable(dssdev);
dsicm_disconnect(dssdev);
omapdss_device_disconnect(dssdev->src, dssdev);
sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);

View file

@ -33,19 +33,11 @@ static const struct videomode lb035q02_vm = {
.vfront_porch = 4,
.vback_porch = 18,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
DISPLAY_FLAGS_PIXDATA_POSEDGE,
/*
* Note: According to the panel documentation:
* DE is active LOW
* DATA needs to be driven on the FALLING edge
*/
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct spi_device *spi;
@ -116,51 +108,25 @@ static void init_lb035q02_panel(struct spi_device *spi)
lb035q02_write_reg(spi, 0x3b, 0x0806);
}
static int lb035q02_connect(struct omap_dss_device *dssdev)
static int lb035q02_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
struct panel_drv_data *ddata = to_panel_data(dst);
init_lb035q02_panel(ddata->spi);
ddata->in = in;
return 0;
}
static void lb035q02_disconnect(struct omap_dss_device *dssdev)
static void lb035q02_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dpi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int lb035q02_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -169,9 +135,7 @@ static int lb035q02_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -186,7 +150,7 @@ static int lb035q02_enable(struct omap_dss_device *dssdev)
static void lb035q02_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
@ -194,23 +158,11 @@ static void lb035q02_disable(struct omap_dss_device *dssdev)
if (ddata->enable_gpio)
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
in->ops.dpi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void lb035q02_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void lb035q02_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -219,25 +171,14 @@ static void lb035q02_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int lb035q02_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dpi->check_timings(in, vm);
}
static struct omap_dss_driver lb035q02_ops = {
static const struct omap_dss_device_ops lb035q02_ops = {
.connect = lb035q02_connect,
.disconnect = lb035q02_disconnect,
.enable = lb035q02_enable,
.disable = lb035q02_disable,
.set_timings = lb035q02_set_timings,
.get_timings = lb035q02_get_timings,
.check_timings = lb035q02_check_timings,
};
static int lb035q02_probe_of(struct spi_device *spi)
@ -278,16 +219,21 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi)
dssdev = &ddata->dssdev;
dssdev->dev = &spi->dev;
dssdev->driver = &lb035q02_ops;
dssdev->ops = &lb035q02_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&spi->dev, "Failed to register panel\n");
return r;
}
/*
* Note: According to the panel documentation:
* DE is active LOW
* DATA needs to be driven on the FALLING edge
*/
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -297,10 +243,9 @@ static int lb035q02_panel_spi_remove(struct spi_device *spi)
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
lb035q02_disable(dssdev);
lb035q02_disconnect(dssdev);
return 0;
}

View file

@ -11,22 +11,19 @@
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include "../dss/omapdss.h"
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct videomode vm;
int res_gpio;
int qvga_gpio;
struct gpio_desc *res_gpio;
struct spi_device *spi;
};
@ -74,9 +71,7 @@ static const struct videomode nec_8048_panel_vm = {
.vsync_len = 1,
.vback_porch = 4,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
DISPLAY_FLAGS_PIXDATA_POSEDGE,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@ -112,49 +107,21 @@ static int init_nec_8048_wvga_lcd(struct spi_device *spi)
return 0;
}
static int nec_8048_connect(struct omap_dss_device *dssdev)
static int nec_8048_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void nec_8048_disconnect(struct omap_dss_device *dssdev)
static void nec_8048_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dpi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int nec_8048_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -163,14 +130,11 @@ static int nec_8048_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
if (gpio_is_valid(ddata->res_gpio))
gpio_set_value_cansleep(ddata->res_gpio, 1);
gpiod_set_value_cansleep(ddata->res_gpio, 1);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@ -180,31 +144,18 @@ static int nec_8048_enable(struct omap_dss_device *dssdev)
static void nec_8048_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
if (gpio_is_valid(ddata->res_gpio))
gpio_set_value_cansleep(ddata->res_gpio, 0);
gpiod_set_value_cansleep(ddata->res_gpio, 0);
in->ops.dpi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void nec_8048_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void nec_8048_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -213,50 +164,21 @@ static void nec_8048_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int nec_8048_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dpi->check_timings(in, vm);
}
static struct omap_dss_driver nec_8048_ops = {
static const struct omap_dss_device_ops nec_8048_ops = {
.connect = nec_8048_connect,
.disconnect = nec_8048_disconnect,
.enable = nec_8048_enable,
.disable = nec_8048_disable,
.set_timings = nec_8048_set_timings,
.get_timings = nec_8048_get_timings,
.check_timings = nec_8048_check_timings,
};
static int nec_8048_probe_of(struct spi_device *spi)
{
struct device_node *node = spi->dev.of_node;
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
int gpio;
gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (!gpio_is_valid(gpio)) {
dev_err(&spi->dev, "failed to parse enable gpio\n");
return gpio;
}
ddata->res_gpio = gpio;
/* XXX the panel spec doesn't mention any QVGA pin?? */
ddata->qvga_gpio = -ENOENT;
return 0;
}
static int nec_8048_probe(struct spi_device *spi)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
struct gpio_desc *gpio;
int r;
dev_dbg(&spi->dev, "%s\n", __func__);
@ -280,38 +202,27 @@ static int nec_8048_probe(struct spi_device *spi)
ddata->spi = spi;
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,
GPIOF_OUT_INIT_HIGH, "lcd QVGA");
if (r)
return r;
gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio)) {
dev_err(&spi->dev, "failed to get reset gpio\n");
return PTR_ERR(gpio);
}
if (gpio_is_valid(ddata->res_gpio)) {
r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
GPIOF_OUT_INIT_LOW, "lcd RES");
if (r)
return r;
}
ddata->res_gpio = gpio;
ddata->vm = nec_8048_panel_vm;
dssdev = &ddata->dssdev;
dssdev->dev = &spi->dev;
dssdev->driver = &nec_8048_ops;
dssdev->ops = &nec_8048_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&spi->dev, "Failed to register panel\n");
return r;
}
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -323,10 +234,9 @@ static int nec_8048_remove(struct spi_device *spi)
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
nec_8048_disable(dssdev);
nec_8048_disconnect(dssdev);
return 0;
}

View file

@ -21,7 +21,6 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct regulator *vcc;
struct videomode vm;
@ -47,60 +46,26 @@ static const struct videomode sharp_ls_vm = {
.vfront_porch = 1,
.vback_porch = 1,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
DISPLAY_FLAGS_PIXDATA_POSEDGE,
/*
* Note: According to the panel documentation:
* DATA needs to be driven on the FALLING edge
*/
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
static int sharp_ls_connect(struct omap_dss_device *dssdev)
static int sharp_ls_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void sharp_ls_disconnect(struct omap_dss_device *dssdev)
static void sharp_ls_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dpi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int sharp_ls_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -109,15 +74,13 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
if (ddata->vcc) {
r = regulator_enable(ddata->vcc);
if (r != 0)
return r;
}
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r) {
regulator_disable(ddata->vcc);
return r;
@ -140,7 +103,7 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev)
static void sharp_ls_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
@ -155,7 +118,7 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
msleep(100);
in->ops.dpi->disable(in);
src->ops->disable(src);
if (ddata->vcc)
regulator_disable(ddata->vcc);
@ -163,18 +126,6 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void sharp_ls_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -183,25 +134,14 @@ static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int sharp_ls_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dpi->check_timings(in, vm);
}
static struct omap_dss_driver sharp_ls_ops = {
static const struct omap_dss_device_ops sharp_ls_ops = {
.connect = sharp_ls_connect,
.disconnect = sharp_ls_disconnect,
.enable = sharp_ls_enable,
.disable = sharp_ls_disable,
.set_timings = sharp_ls_set_timings,
.get_timings = sharp_ls_get_timings,
.check_timings = sharp_ls_check_timings,
};
static int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
@ -278,16 +218,20 @@ static int sharp_ls_probe(struct platform_device *pdev)
dssdev = &ddata->dssdev;
dssdev->dev = &pdev->dev;
dssdev->driver = &sharp_ls_ops;
dssdev->ops = &sharp_ls_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register panel\n");
return r;
}
/*
* Note: According to the panel documentation:
* DATA needs to be driven on the FALLING edge
*/
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -297,10 +241,9 @@ static int __exit sharp_ls_remove(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
sharp_ls_disable(dssdev);
sharp_ls_disconnect(dssdev);
return 0;
}

View file

@ -20,17 +20,15 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/backlight.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include "../dss/omapdss.h"
@ -64,9 +62,8 @@
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
int reset_gpio;
struct gpio_desc *reset_gpio;
struct videomode vm;
@ -100,9 +97,7 @@ static const struct videomode acx565akm_panel_vm = {
.vsync_len = 3,
.vback_porch = 4,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_NEGEDGE |
DISPLAY_FLAGS_PIXDATA_POSEDGE,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@ -507,56 +502,26 @@ static const struct attribute_group bldev_attr_group = {
.attrs = bldev_attrs,
};
static int acx565akm_connect(struct omap_dss_device *dssdev)
static int acx565akm_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.sdi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void acx565akm_disconnect(struct omap_dss_device *dssdev)
static void acx565akm_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.sdi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
in->ops.sdi->set_timings(in, &ddata->vm);
r = in->ops.sdi->enable(in);
r = src->ops->enable(src);
if (r) {
pr_err("%s sdi enable failed\n", __func__);
return r;
@ -565,8 +530,8 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
/*FIXME tweak me */
msleep(50);
if (gpio_is_valid(ddata->reset_gpio))
gpio_set_value(ddata->reset_gpio, 1);
if (ddata->reset_gpio)
gpiod_set_value(ddata->reset_gpio, 1);
if (ddata->enabled) {
dev_dbg(&ddata->spi->dev, "panel already enabled\n");
@ -597,7 +562,7 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
dev_dbg(dssdev->dev, "%s\n", __func__);
@ -615,13 +580,13 @@ static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
*/
msleep(50);
if (gpio_is_valid(ddata->reset_gpio))
gpio_set_value(ddata->reset_gpio, 0);
if (ddata->reset_gpio)
gpiod_set_value(ddata->reset_gpio, 0);
/* FIXME need to tweak this delay */
msleep(100);
in->ops.sdi->disable(in);
src->ops->disable(src);
}
static int acx565akm_enable(struct omap_dss_device *dssdev)
@ -664,18 +629,6 @@ static void acx565akm_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void acx565akm_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.sdi->set_timings(in, vm);
}
static void acx565akm_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -684,37 +637,16 @@ static void acx565akm_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int acx565akm_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.sdi->check_timings(in, vm);
}
static struct omap_dss_driver acx565akm_ops = {
static const struct omap_dss_device_ops acx565akm_ops = {
.connect = acx565akm_connect,
.disconnect = acx565akm_disconnect,
.enable = acx565akm_enable,
.disable = acx565akm_disable,
.set_timings = acx565akm_set_timings,
.get_timings = acx565akm_get_timings,
.check_timings = acx565akm_check_timings,
};
static int acx565akm_probe_of(struct spi_device *spi)
{
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
struct device_node *np = spi->dev.of_node;
ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
return 0;
}
static int acx565akm_probe(struct spi_device *spi)
{
struct panel_drv_data *ddata;
@ -722,6 +654,7 @@ static int acx565akm_probe(struct spi_device *spi)
struct backlight_device *bldev;
int max_brightness, brightness;
struct backlight_properties props;
struct gpio_desc *gpio;
int r;
dev_dbg(&spi->dev, "%s\n", __func__);
@ -738,19 +671,16 @@ static int acx565akm_probe(struct spi_device *spi)
mutex_init(&ddata->mutex);
r = acx565akm_probe_of(spi);
if (r)
return r;
if (gpio_is_valid(ddata->reset_gpio)) {
r = devm_gpio_request_one(&spi->dev, ddata->reset_gpio,
GPIOF_OUT_INIT_LOW, "lcd reset");
if (r)
goto err_gpio;
gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio)) {
dev_err(&spi->dev, "failed to parse reset gpio\n");
return PTR_ERR(gpio);
}
if (gpio_is_valid(ddata->reset_gpio))
gpio_set_value(ddata->reset_gpio, 1);
ddata->reset_gpio = gpio;
if (ddata->reset_gpio)
gpiod_set_value(ddata->reset_gpio, 1);
/*
* After reset we have to wait 5 msec before the first
@ -762,12 +692,12 @@ static int acx565akm_probe(struct spi_device *spi)
r = panel_detect(ddata);
if (!ddata->enabled && gpio_is_valid(ddata->reset_gpio))
gpio_set_value(ddata->reset_gpio, 0);
if (!ddata->enabled && ddata->reset_gpio)
gpiod_set_value(ddata->reset_gpio, 0);
if (r) {
dev_err(&spi->dev, "%s panel detect error\n", __func__);
goto err_detect;
return r;
}
memset(&props, 0, sizeof(props));
@ -777,17 +707,15 @@ static int acx565akm_probe(struct spi_device *spi)
bldev = backlight_device_register("acx565akm", &ddata->spi->dev,
ddata, &acx565akm_bl_ops, &props);
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
goto err_reg_bl;
}
if (IS_ERR(bldev))
return PTR_ERR(bldev);
ddata->bl_dev = bldev;
if (ddata->has_cabc) {
r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
if (r) {
dev_err(&bldev->dev,
"%s failed to create sysfs files\n", __func__);
goto err_sysfs;
goto err_backlight_unregister;
}
ddata->cabc_mode = get_hw_cabc_mode(ddata);
}
@ -809,26 +737,20 @@ static int acx565akm_probe(struct spi_device *spi)
dssdev = &ddata->dssdev;
dssdev->dev = &spi->dev;
dssdev->driver = &acx565akm_ops;
dssdev->ops = &acx565akm_ops;
dssdev->type = OMAP_DISPLAY_TYPE_SDI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&spi->dev, "Failed to register panel\n");
goto err_reg;
}
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
err_reg:
sysfs_remove_group(&bldev->dev.kobj, &bldev_attr_group);
err_sysfs:
err_backlight_unregister:
backlight_device_unregister(bldev);
err_reg_bl:
err_detect:
err_gpio:
return r;
}
@ -842,10 +764,9 @@ static int acx565akm_remove(struct spi_device *spi)
sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group);
backlight_device_unregister(ddata->bl_dev);
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
acx565akm_disable(dssdev);
acx565akm_disconnect(dssdev);
return 0;
}

View file

@ -27,13 +27,11 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include "../dss/omapdss.h"
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct videomode vm;
@ -51,13 +49,7 @@ static const struct videomode td028ttec1_panel_vm = {
.vsync_len = 2,
.vback_porch = 2,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
DISPLAY_FLAGS_PIXDATA_NEGEDGE,
/*
* Note: According to the panel documentation:
* SYNC needs to be driven on the FALLING edge
*/
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
#define JBT_COMMAND 0x000
@ -166,49 +158,21 @@ enum jbt_register {
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
static int td028ttec1_panel_connect(struct omap_dss_device *dssdev)
static int td028ttec1_panel_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void td028ttec1_panel_disconnect(struct omap_dss_device *dssdev)
static void td028ttec1_panel_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dpi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -217,9 +181,7 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -316,7 +278,7 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
@ -328,23 +290,11 @@ static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN);
jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
in->ops.dpi->disable(in);
src->ops->disable(src);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void td028ttec1_panel_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -353,25 +303,14 @@ static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int td028ttec1_panel_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dpi->check_timings(in, vm);
}
static struct omap_dss_driver td028ttec1_ops = {
static const struct omap_dss_device_ops td028ttec1_ops = {
.connect = td028ttec1_panel_connect,
.disconnect = td028ttec1_panel_disconnect,
.enable = td028ttec1_panel_enable,
.disable = td028ttec1_panel_disable,
.set_timings = td028ttec1_panel_set_timings,
.get_timings = td028ttec1_panel_get_timings,
.check_timings = td028ttec1_panel_check_timings,
};
static int td028ttec1_panel_probe(struct spi_device *spi)
@ -403,16 +342,20 @@ static int td028ttec1_panel_probe(struct spi_device *spi)
dssdev = &ddata->dssdev;
dssdev->dev = &spi->dev;
dssdev->driver = &td028ttec1_ops;
dssdev->ops = &td028ttec1_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&spi->dev, "Failed to register panel\n");
return r;
}
/*
* Note: According to the panel documentation:
* SYNC needs to be driven on the FALLING edge
*/
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
| DRM_BUS_FLAG_PIXDATA_NEGEDGE;
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
}
@ -424,10 +367,9 @@ static int td028ttec1_panel_remove(struct spi_device *spi)
dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__);
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
td028ttec1_panel_disable(dssdev);
td028ttec1_panel_disconnect(dssdev);
return 0;
}

View file

@ -10,14 +10,13 @@
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include "../dss/omapdss.h"
@ -54,16 +53,14 @@ static const u16 tpo_td043_def_gamma[12] = {
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct videomode vm;
struct spi_device *spi;
struct regulator *vcc_reg;
int nreset_gpio;
struct gpio_desc *reset_gpio;
u16 gamma[12];
u32 mode;
u32 hmirror:1;
u32 vmirror:1;
u32 powered_on:1;
u32 spi_suspended:1;
@ -84,13 +81,7 @@ static const struct videomode tpo_td043_vm = {
.vfront_porch = 39,
.vback_porch = 34,
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
DISPLAY_FLAGS_PIXDATA_NEGEDGE,
/*
* Note: According to the panel documentation:
* SYNC needs to be driven on the FALLING edge
*/
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
};
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@ -152,22 +143,6 @@ static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
return tpo_td043_write(spi, 4, reg4);
}
static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
{
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
ddata->hmirror = enable;
return tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
ddata->vmirror);
}
static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(dssdev->dev);
return ddata->hmirror;
}
static ssize_t tpo_td043_vmirror_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -189,7 +164,7 @@ static ssize_t tpo_td043_vmirror_store(struct device *dev,
val = !!val;
ret = tpo_td043_write_mirror(ddata->spi, ddata->hmirror, val);
ret = tpo_td043_write_mirror(ddata->spi, false, val);
if (ret < 0)
return ret;
@ -300,16 +275,14 @@ static int tpo_td043_power_on(struct panel_drv_data *ddata)
/* wait for panel to stabilize */
msleep(160);
if (gpio_is_valid(ddata->nreset_gpio))
gpio_set_value(ddata->nreset_gpio, 1);
gpiod_set_value(ddata->reset_gpio, 0);
tpo_td043_write(ddata->spi, 2,
TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING);
tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL);
tpo_td043_write(ddata->spi, 0x20, 0xf0);
tpo_td043_write(ddata->spi, 0x21, 0xf0);
tpo_td043_write_mirror(ddata->spi, ddata->hmirror,
ddata->vmirror);
tpo_td043_write_mirror(ddata->spi, false, ddata->vmirror);
tpo_td043_write_gamma(ddata->spi, ddata->gamma);
ddata->powered_on = 1;
@ -324,8 +297,7 @@ static void tpo_td043_power_off(struct panel_drv_data *ddata)
tpo_td043_write(ddata->spi, 3,
TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
if (gpio_is_valid(ddata->nreset_gpio))
gpio_set_value(ddata->nreset_gpio, 0);
gpiod_set_value(ddata->reset_gpio, 1);
/* wait for at least 2 vsyncs before cutting off power */
msleep(50);
@ -337,49 +309,21 @@ static void tpo_td043_power_off(struct panel_drv_data *ddata)
ddata->powered_on = 0;
}
static int tpo_td043_connect(struct omap_dss_device *dssdev)
static int tpo_td043_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in;
int r;
if (omapdss_device_is_connected(dssdev))
return 0;
in = omapdss_of_find_source_for_first_ep(dssdev->dev->of_node);
if (IS_ERR(in)) {
dev_err(dssdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
r = in->ops.dpi->connect(in, dssdev);
if (r) {
omap_dss_put_device(in);
return r;
}
ddata->in = in;
return 0;
}
static void tpo_td043_disconnect(struct omap_dss_device *dssdev)
static void tpo_td043_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_connected(dssdev))
return;
in->ops.dpi->disconnect(in, dssdev);
omap_dss_put_device(in);
ddata->in = NULL;
}
static int tpo_td043_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
int r;
if (!omapdss_device_is_connected(dssdev))
@ -388,9 +332,7 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.dpi->set_timings(in, &ddata->vm);
r = in->ops.dpi->enable(in);
r = src->ops->enable(src);
if (r)
return r;
@ -401,7 +343,7 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
if (!ddata->spi_suspended) {
r = tpo_td043_power_on(ddata);
if (r) {
in->ops.dpi->disable(in);
src->ops->disable(src);
return r;
}
}
@ -414,12 +356,12 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
static void tpo_td043_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
struct omap_dss_device *src = dssdev->src;
if (!omapdss_device_is_enabled(dssdev))
return;
in->ops.dpi->disable(in);
src->ops->disable(src);
if (!ddata->spi_suspended)
tpo_td043_power_off(ddata);
@ -427,18 +369,6 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
ddata->vm = *vm;
dssdev->panel.vm = *vm;
in->ops.dpi->set_timings(in, vm);
}
static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
@ -447,50 +377,21 @@ static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
*vm = ddata->vm;
}
static int tpo_td043_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.dpi->check_timings(in, vm);
}
static struct omap_dss_driver tpo_td043_ops = {
static const struct omap_dss_device_ops tpo_td043_ops = {
.connect = tpo_td043_connect,
.disconnect = tpo_td043_disconnect,
.enable = tpo_td043_enable,
.disable = tpo_td043_disable,
.set_timings = tpo_td043_set_timings,
.get_timings = tpo_td043_get_timings,
.check_timings = tpo_td043_check_timings,
.set_mirror = tpo_td043_set_hmirror,
.get_mirror = tpo_td043_get_hmirror,
};
static int tpo_td043_probe_of(struct spi_device *spi)
{
struct device_node *node = spi->dev.of_node;
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
int gpio;
gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (!gpio_is_valid(gpio)) {
dev_err(&spi->dev, "failed to parse enable gpio\n");
return gpio;
}
ddata->nreset_gpio = gpio;
return 0;
}
static int tpo_td043_probe(struct spi_device *spi)
{
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev;
struct gpio_desc *gpio;
int r;
dev_dbg(&spi->dev, "%s\n", __func__);
@ -512,59 +413,49 @@ static int tpo_td043_probe(struct spi_device *spi)
ddata->spi = spi;
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));
ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc");
if (IS_ERR(ddata->vcc_reg)) {
dev_err(&spi->dev, "failed to get LCD VCC regulator\n");
r = PTR_ERR(ddata->vcc_reg);
goto err_regulator;
return PTR_ERR(ddata->vcc_reg);
}
if (gpio_is_valid(ddata->nreset_gpio)) {
r = devm_gpio_request_one(&spi->dev,
ddata->nreset_gpio, GPIOF_OUT_INIT_LOW,
"lcd reset");
if (r < 0) {
dev_err(&spi->dev, "couldn't request reset GPIO\n");
goto err_gpio_req;
}
gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(gpio)) {
dev_err(&spi->dev, "failed to get reset gpio\n");
return PTR_ERR(gpio);
}
ddata->reset_gpio = gpio;
r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group);
if (r) {
dev_err(&spi->dev, "failed to create sysfs files\n");
goto err_sysfs;
return r;
}
ddata->vm = tpo_td043_vm;
dssdev = &ddata->dssdev;
dssdev->dev = &spi->dev;
dssdev->driver = &tpo_td043_ops;
dssdev->ops = &tpo_td043_ops;
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
dssdev->owner = THIS_MODULE;
dssdev->panel.vm = ddata->vm;
dssdev->of_ports = BIT(0);
r = omapdss_register_display(dssdev);
if (r) {
dev_err(&spi->dev, "Failed to register panel\n");
goto err_reg;
}
/*
* Note: According to the panel documentation:
* SYNC needs to be driven on the FALLING edge
*/
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
| DRM_BUS_FLAG_PIXDATA_NEGEDGE;
omapdss_display_init(dssdev);
omapdss_device_register(dssdev);
return 0;
err_reg:
sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
err_sysfs:
err_gpio_req:
err_regulator:
return r;
}
static int tpo_td043_remove(struct spi_device *spi)
@ -574,10 +465,9 @@ static int tpo_td043_remove(struct spi_device *spi)
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
omapdss_unregister_display(dssdev);
omapdss_device_unregister(dssdev);
tpo_td043_disable(dssdev);
tpo_td043_disconnect(dssdev);
sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);

View file

@ -14,24 +14,17 @@
*/
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/list.h>
#include "dss.h"
#include "omapdss.h"
static struct dss_device *dss_device;
static struct list_head omapdss_comp_list;
struct omapdss_comp_node {
struct list_head list;
struct device_node *node;
bool dss_core_component;
};
struct dss_device *omapdss_get_dss(void)
{
return dss_device;
@ -56,6 +49,208 @@ const struct dispc_ops *dispc_get_ops(struct dss_device *dss)
}
EXPORT_SYMBOL(dispc_get_ops);
/* -----------------------------------------------------------------------------
* OMAP DSS Devices Handling
*/
static LIST_HEAD(omapdss_devices_list);
static DEFINE_MUTEX(omapdss_devices_lock);
void omapdss_device_register(struct omap_dss_device *dssdev)
{
mutex_lock(&omapdss_devices_lock);
list_add_tail(&dssdev->list, &omapdss_devices_list);
mutex_unlock(&omapdss_devices_lock);
}
EXPORT_SYMBOL_GPL(omapdss_device_register);
void omapdss_device_unregister(struct omap_dss_device *dssdev)
{
mutex_lock(&omapdss_devices_lock);
list_del(&dssdev->list);
mutex_unlock(&omapdss_devices_lock);
}
EXPORT_SYMBOL_GPL(omapdss_device_unregister);
static bool omapdss_device_is_registered(struct device_node *node)
{
struct omap_dss_device *dssdev;
bool found = false;
mutex_lock(&omapdss_devices_lock);
list_for_each_entry(dssdev, &omapdss_devices_list, list) {
if (dssdev->dev->of_node == node) {
found = true;
break;
}
}
mutex_unlock(&omapdss_devices_lock);
return found;
}
struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev)
{
if (!try_module_get(dssdev->owner))
return NULL;
if (get_device(dssdev->dev) == NULL) {
module_put(dssdev->owner);
return NULL;
}
return dssdev;
}
EXPORT_SYMBOL(omapdss_device_get);
void omapdss_device_put(struct omap_dss_device *dssdev)
{
put_device(dssdev->dev);
module_put(dssdev->owner);
}
EXPORT_SYMBOL(omapdss_device_put);
struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
unsigned int port)
{
struct omap_dss_device *dssdev;
list_for_each_entry(dssdev, &omapdss_devices_list, list) {
if (dssdev->dev->of_node == src && dssdev->of_ports & BIT(port))
return omapdss_device_get(dssdev);
}
return NULL;
}
/*
* Search for the next device starting at @from. The type argument specfies
* which device types to consider when searching. Searching for multiple types
* is supported by and'ing their type flags. Release the reference to the @from
* device, and acquire a reference to the returned device if found.
*/
struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
enum omap_dss_device_type type)
{
struct omap_dss_device *dssdev;
struct list_head *list;
mutex_lock(&omapdss_devices_lock);
if (list_empty(&omapdss_devices_list)) {
dssdev = NULL;
goto done;
}
/*
* Start from the from entry if given or from omapdss_devices_list
* otherwise.
*/
list = from ? &from->list : &omapdss_devices_list;
list_for_each_entry(dssdev, list, list) {
/*
* Stop if we reach the omapdss_devices_list, that's the end of
* the list.
*/
if (&dssdev->list == &omapdss_devices_list) {
dssdev = NULL;
goto done;
}
/*
* Accept display entities if the display type is requested,
* and output entities if the output type is requested.
*/
if ((type & OMAP_DSS_DEVICE_TYPE_DISPLAY) &&
!dssdev->output_type)
goto done;
if ((type & OMAP_DSS_DEVICE_TYPE_OUTPUT) && dssdev->id &&
dssdev->next)
goto done;
}
dssdev = NULL;
done:
if (from)
omapdss_device_put(from);
if (dssdev)
omapdss_device_get(dssdev);
mutex_unlock(&omapdss_devices_lock);
return dssdev;
}
EXPORT_SYMBOL(omapdss_device_get_next);
int omapdss_device_connect(struct dss_device *dss,
struct omap_dss_device *src,
struct omap_dss_device *dst)
{
int ret;
dev_dbg(dst->dev, "connect\n");
if (omapdss_device_is_connected(dst))
return -EBUSY;
dst->dss = dss;
ret = dst->ops->connect(src, dst);
if (ret < 0) {
dst->dss = NULL;
return ret;
}
if (src) {
WARN_ON(src->dst);
dst->src = src;
src->dst = dst;
}
return 0;
}
EXPORT_SYMBOL_GPL(omapdss_device_connect);
void omapdss_device_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
dev_dbg(dst->dev, "disconnect\n");
if (!dst->id && !omapdss_device_is_connected(dst)) {
WARN_ON(dst->output_type);
return;
}
if (src) {
if (WARN_ON(dst != src->dst))
return;
dst->src = NULL;
src->dst = NULL;
}
WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
dst->ops->disconnect(src, dst);
dst->dss = NULL;
}
EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
/* -----------------------------------------------------------------------------
* Components Handling
*/
static struct list_head omapdss_comp_list;
struct omapdss_comp_node {
struct list_head list;
struct device_node *node;
bool dss_core_component;
};
static bool omapdss_list_contains(const struct device_node *node)
{
struct omapdss_comp_node *comp;
@ -130,9 +325,7 @@ static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
{
if (comp->dss_core_component)
return true;
if (omapdss_component_is_display(comp->node))
return true;
if (omapdss_component_is_output(comp->node))
if (omapdss_device_is_registered(comp->node))
return true;
return false;

View file

@ -45,36 +45,14 @@ static struct platform_driver * const omap_dss_drivers[] = {
#endif
};
static struct platform_device *omap_drm_device;
static int __init omap_dss_init(void)
{
int r;
r = platform_register_drivers(omap_dss_drivers,
ARRAY_SIZE(omap_dss_drivers));
if (r)
goto err_reg;
omap_drm_device = platform_device_register_simple("omapdrm", 0, NULL, 0);
if (IS_ERR(omap_drm_device)) {
r = PTR_ERR(omap_drm_device);
goto err_reg;
}
return 0;
err_reg:
platform_unregister_drivers(omap_dss_drivers,
ARRAY_SIZE(omap_dss_drivers));
return r;
return platform_register_drivers(omap_dss_drivers,
ARRAY_SIZE(omap_dss_drivers));
}
static void __exit omap_dss_exit(void)
{
platform_device_unregister(omap_drm_device);
platform_unregister_drivers(omap_dss_drivers,
ARRAY_SIZE(omap_dss_drivers));
}

View file

@ -2904,13 +2904,6 @@ static int dispc_ovl_enable(struct dispc_device *dispc,
return 0;
}
static enum omap_dss_output_id
dispc_mgr_get_supported_outputs(struct dispc_device *dispc,
enum omap_channel channel)
{
return dss_get_supported_outputs(dispc->dss, channel);
}
static void dispc_lcd_enable_signal_polarity(struct dispc_device *dispc,
bool act_high)
{
@ -3120,28 +3113,29 @@ static bool _dispc_mgr_pclk_ok(struct dispc_device *dispc,
return pclk <= dispc->feat->max_tv_pclk;
}
bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel,
const struct videomode *vm)
static int dispc_mgr_check_timings(struct dispc_device *dispc,
enum omap_channel channel,
const struct videomode *vm)
{
if (!_dispc_mgr_size_ok(dispc, vm->hactive, vm->vactive))
return false;
return MODE_BAD;
if (!_dispc_mgr_pclk_ok(dispc, channel, vm->pixelclock))
return false;
return MODE_BAD;
if (dss_mgr_is_lcd(channel)) {
/* TODO: OMAP4+ supports interlace for LCD outputs */
if (vm->flags & DISPLAY_FLAGS_INTERLACED)
return false;
return MODE_BAD;
if (!_dispc_lcd_timings_ok(dispc, vm->hsync_len,
vm->hfront_porch, vm->hback_porch,
vm->vsync_len, vm->vfront_porch,
vm->vback_porch))
return false;
return MODE_BAD;
}
return true;
return MODE_OK;
}
static void _dispc_mgr_set_lcd_timings(struct dispc_device *dispc,
@ -3243,7 +3237,7 @@ static void dispc_mgr_set_timings(struct dispc_device *dispc,
DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
if (!dispc_mgr_timings_ok(dispc, channel, &t)) {
if (dispc_mgr_check_timings(dispc, channel, &t)) {
BUG();
return;
}
@ -4740,9 +4734,9 @@ static const struct dispc_ops dispc_ops = {
.mgr_go_busy = dispc_mgr_go_busy,
.mgr_go = dispc_mgr_go,
.mgr_set_lcd_config = dispc_mgr_set_lcd_config,
.mgr_check_timings = dispc_mgr_check_timings,
.mgr_set_timings = dispc_mgr_set_timings,
.mgr_setup = dispc_mgr_setup,
.mgr_get_supported_outputs = dispc_mgr_get_supported_outputs,
.mgr_gamma_size = dispc_mgr_gamma_size,
.mgr_set_gamma = dispc_mgr_set_gamma,

View file

@ -21,27 +21,14 @@
#define DSS_SUBSYS_NAME "DISPLAY"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include "omapdss.h"
static void omapdss_default_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
*vm = dssdev->panel.vm;
}
static LIST_HEAD(panel_list);
static DEFINE_MUTEX(panel_list_mutex);
static int disp_num_counter;
int omapdss_register_display(struct omap_dss_device *dssdev)
void omapdss_display_init(struct omap_dss_device *dssdev)
{
struct omap_dss_driver *drv = dssdev->driver;
struct list_head *cur;
int id;
/*
@ -52,123 +39,22 @@ int omapdss_register_display(struct omap_dss_device *dssdev)
if (id < 0)
id = disp_num_counter++;
snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
dssdev->alias_id = id;
/* Use 'label' property for name, if it exists */
of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name);
if (dssdev->name == NULL)
dssdev->name = dssdev->alias;
if (drv && drv->get_timings == NULL)
drv->get_timings = omapdss_default_get_timings;
mutex_lock(&panel_list_mutex);
list_for_each(cur, &panel_list) {
struct omap_dss_device *ldev = list_entry(cur,
struct omap_dss_device,
panel_list);
if (strcmp(ldev->alias, dssdev->alias) > 0)
break;
}
list_add_tail(&dssdev->panel_list, cur);
mutex_unlock(&panel_list_mutex);
return 0;
dssdev->name = devm_kasprintf(dssdev->dev, GFP_KERNEL,
"display%u", id);
}
EXPORT_SYMBOL(omapdss_register_display);
EXPORT_SYMBOL_GPL(omapdss_display_init);
void omapdss_unregister_display(struct omap_dss_device *dssdev)
struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output)
{
mutex_lock(&panel_list_mutex);
list_del(&dssdev->panel_list);
mutex_unlock(&panel_list_mutex);
while (output->next)
output = output->next;
return omapdss_device_get(output);
}
EXPORT_SYMBOL(omapdss_unregister_display);
bool omapdss_component_is_display(struct device_node *node)
{
struct omap_dss_device *dssdev;
bool found = false;
mutex_lock(&panel_list_mutex);
list_for_each_entry(dssdev, &panel_list, panel_list) {
if (dssdev->dev->of_node == node) {
found = true;
goto out;
}
}
out:
mutex_unlock(&panel_list_mutex);
return found;
}
EXPORT_SYMBOL(omapdss_component_is_display);
struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
{
if (!try_module_get(dssdev->owner))
return NULL;
if (get_device(dssdev->dev) == NULL) {
module_put(dssdev->owner);
return NULL;
}
return dssdev;
}
EXPORT_SYMBOL(omap_dss_get_device);
void omap_dss_put_device(struct omap_dss_device *dssdev)
{
put_device(dssdev->dev);
module_put(dssdev->owner);
}
EXPORT_SYMBOL(omap_dss_put_device);
/*
* ref count of the found device is incremented.
* ref count of from-device is decremented.
*/
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
{
struct list_head *l;
struct omap_dss_device *dssdev;
mutex_lock(&panel_list_mutex);
if (list_empty(&panel_list)) {
dssdev = NULL;
goto out;
}
if (from == NULL) {
dssdev = list_first_entry(&panel_list, struct omap_dss_device,
panel_list);
omap_dss_get_device(dssdev);
goto out;
}
omap_dss_put_device(from);
list_for_each(l, &panel_list) {
dssdev = list_entry(l, struct omap_dss_device, panel_list);
if (dssdev == from) {
if (list_is_last(l, &panel_list)) {
dssdev = NULL;
goto out;
}
dssdev = list_entry(l->next, struct omap_dss_device,
panel_list);
omap_dss_get_device(dssdev);
goto out;
}
}
WARN(1, "'from' dssdev not found\n");
dssdev = NULL;
out:
mutex_unlock(&panel_list_mutex);
return dssdev;
}
EXPORT_SYMBOL(omap_dss_get_next_device);
EXPORT_SYMBOL_GPL(omapdss_display_get);

View file

@ -39,6 +39,7 @@ struct dpi_data {
struct platform_device *pdev;
enum dss_model dss_model;
struct dss_device *dss;
unsigned int id;
struct regulator *vdds_dsi_reg;
enum dss_clk_source clk_src;
@ -346,10 +347,9 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
static int dpi_set_mode(struct dpi_data *dpi)
{
struct videomode *vm = &dpi->vm;
const struct videomode *vm = &dpi->vm;
int lck_div = 0, pck_div = 0;
unsigned long fck = 0;
unsigned long pck;
int r = 0;
if (dpi->pll)
@ -361,17 +361,6 @@ static int dpi_set_mode(struct dpi_data *dpi)
if (r)
return r;
pck = fck / lck_div / pck_div;
if (pck != vm->pixelclock) {
DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
vm->pixelclock, pck);
vm->pixelclock = pck;
}
dss_mgr_set_timings(&dpi->output, vm);
return 0;
}
@ -413,7 +402,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
r = dss_dpi_select_source(dpi->dss, out->port_num, out->dispc_channel);
r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
if (r)
goto err_src_sel;
@ -478,7 +467,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
}
static void dpi_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
const struct videomode *vm)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
@ -491,23 +480,10 @@ static void dpi_set_timings(struct omap_dss_device *dssdev,
mutex_unlock(&dpi->lock);
}
static void dpi_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
mutex_lock(&dpi->lock);
*vm = dpi->vm;
mutex_unlock(&dpi->lock);
}
static int dpi_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
enum omap_channel channel = dpi->output.dispc_channel;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
@ -517,9 +493,6 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
if (vm->hactive % 8 != 0)
return -EINVAL;
if (!dispc_mgr_timings_ok(dpi->dss->dispc, channel, vm))
return -EINVAL;
if (vm->pixelclock == 0)
return -EINVAL;
@ -562,38 +535,6 @@ static int dpi_verify_pll(struct dss_pll *pll)
return 0;
}
static const struct soc_device_attribute dpi_soc_devices[] = {
{ .machine = "OMAP3[456]*" },
{ .machine = "[AD]M37*" },
{ /* sentinel */ }
};
static int dpi_init_regulator(struct dpi_data *dpi)
{
struct regulator *vdds_dsi;
/*
* The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
* DM37xx only.
*/
if (!soc_device_match(dpi_soc_devices))
return 0;
if (dpi->vdds_dsi_reg)
return 0;
vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
if (IS_ERR(vdds_dsi)) {
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi);
}
dpi->vdds_dsi_reg = vdds_dsi;
return 0;
}
static void dpi_init_pll(struct dpi_data *dpi)
{
struct dss_pll *pll;
@ -621,7 +562,7 @@ static void dpi_init_pll(struct dpi_data *dpi)
* the channel in some more dynamic manner, or get the channel as a user
* parameter.
*/
static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
{
switch (dpi->dss_model) {
case DSS_MODEL_OMAP2:
@ -629,7 +570,7 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
return OMAP_DSS_CHANNEL_LCD;
case DSS_MODEL_DRA7:
switch (port_num) {
switch (dpi->id) {
case 2:
return OMAP_DSS_CHANNEL_LCD3;
case 1:
@ -651,49 +592,31 @@ static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
}
}
static int dpi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int dpi_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
int r;
r = dpi_init_regulator(dpi);
if (r)
return r;
dpi_init_pll(dpi);
r = dss_mgr_connect(&dpi->output, dssdev);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
r = omapdss_output_set_device(dssdev, dst);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dst->name);
dss_mgr_disconnect(&dpi->output, dssdev);
return r;
}
dst->dispc_channel_connected = true;
return 0;
}
static void dpi_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void dpi_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
dst->dispc_channel_connected = false;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
omapdss_output_unset_device(dssdev);
dss_mgr_disconnect(&dpi->output, dssdev);
omapdss_device_disconnect(dst, dst->next);
}
static const struct omapdss_dpi_ops dpi_ops = {
static const struct omap_dss_device_ops dpi_ops = {
.connect = dpi_connect,
.disconnect = dpi_disconnect,
@ -702,18 +625,16 @@ static const struct omapdss_dpi_ops dpi_ops = {
.check_timings = dpi_check_timings,
.set_timings = dpi_set_timings,
.get_timings = dpi_get_timings,
};
static void dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
{
struct omap_dss_device *out = &dpi->output;
u32 port_num = 0;
int r;
u32 port_num;
r = of_property_read_u32(port, "reg", &port_num);
if (r)
port_num = 0;
of_property_read_u32(port, "reg", &port_num);
dpi->id = port_num <= 2 ? port_num : 0;
switch (port_num) {
case 2:
@ -731,12 +652,28 @@ static void dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
out->dev = &dpi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->output_type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(dpi, port_num);
out->port_num = port_num;
out->ops.dpi = &dpi_ops;
out->dispc_channel = dpi_get_channel(dpi);
out->of_ports = BIT(port_num);
out->ops = &dpi_ops;
out->owner = THIS_MODULE;
omapdss_register_output(out);
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
}
r = omapdss_output_validate(out);
if (r) {
omapdss_device_put(out->next);
out->next = NULL;
return r;
}
omapdss_device_register(out);
return 0;
}
static void dpi_uninit_output_port(struct device_node *port)
@ -744,7 +681,38 @@ static void dpi_uninit_output_port(struct device_node *port)
struct dpi_data *dpi = port->data;
struct omap_dss_device *out = &dpi->output;
omapdss_unregister_output(out);
if (out->next)
omapdss_device_put(out->next);
omapdss_device_unregister(out);
}
static const struct soc_device_attribute dpi_soc_devices[] = {
{ .machine = "OMAP3[456]*" },
{ .machine = "[AD]M37*" },
{ /* sentinel */ }
};
static int dpi_init_regulator(struct dpi_data *dpi)
{
struct regulator *vdds_dsi;
/*
* The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
* DM37xx only.
*/
if (!soc_device_match(dpi_soc_devices))
return 0;
vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
if (IS_ERR(vdds_dsi)) {
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi);
}
dpi->vdds_dsi_reg = vdds_dsi;
return 0;
}
int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
@ -764,15 +732,14 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
return 0;
r = of_property_read_u32(ep, "data-lines", &datalines);
of_node_put(ep);
if (r) {
DSSERR("failed to parse datalines\n");
goto err_datalines;
return r;
}
dpi->data_lines = datalines;
of_node_put(ep);
dpi->pdev = pdev;
dpi->dss_model = dss_model;
dpi->dss = dss;
@ -780,14 +747,11 @@ int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
mutex_init(&dpi->lock);
dpi_init_output_port(dpi, port);
r = dpi_init_regulator(dpi);
if (r)
return r;
return 0;
err_datalines:
of_node_put(ep);
return r;
return dpi_init_output_port(dpi, port);
}
void dpi_uninit_port(struct device_node *port)

View file

@ -403,6 +403,7 @@ struct dsi_data {
struct {
struct dss_debugfs_entry *irqs;
struct dss_debugfs_entry *regs;
struct dss_debugfs_entry *clks;
} debugfs;
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@ -442,27 +443,6 @@ static inline struct dsi_data *to_dsi_data(struct omap_dss_device *dssdev)
return dev_get_drvdata(dssdev->dev);
}
static struct dsi_data *dsi_get_dsi_from_id(int module)
{
struct omap_dss_device *out;
enum omap_dss_output_id id;
switch (module) {
case 0:
id = OMAP_DSS_OUTPUT_DSI1;
break;
case 1:
id = OMAP_DSS_OUTPUT_DSI2;
break;
default:
return NULL;
}
out = omap_dss_get_output(id);
return out ? to_dsi_data(out) : NULL;
}
static inline void dsi_write_reg(struct dsi_data *dsi,
const struct dsi_reg idx, u32 val)
{
@ -1157,26 +1137,6 @@ static void dsi_runtime_put(struct dsi_data *dsi)
WARN_ON(r < 0 && r != -ENOSYS);
}
static int dsi_regulator_init(struct dsi_data *dsi)
{
struct regulator *vdds_dsi;
if (dsi->vdds_dsi_reg != NULL)
return 0;
vdds_dsi = devm_regulator_get(dsi->dev, "vdd");
if (IS_ERR(vdds_dsi)) {
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
DSSERR("can't get DSI VDD regulator\n");
return PTR_ERR(vdds_dsi);
}
dsi->vdds_dsi_reg = vdds_dsi;
return 0;
}
static void _dsi_print_reset_status(struct dsi_data *dsi)
{
u32 l;
@ -1373,10 +1333,6 @@ static int dsi_pll_enable(struct dss_pll *pll)
DSSDBG("PLL init\n");
r = dsi_regulator_init(dsi);
if (r)
return r;
r = dsi_runtime_get(dsi);
if (r)
return r;
@ -1448,8 +1404,9 @@ static void dsi_pll_disable(struct dss_pll *pll)
dsi_pll_uninit(dsi, true);
}
static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s)
static int dsi_dump_dsi_clocks(struct seq_file *s, void *p)
{
struct dsi_data *dsi = p;
struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
enum dss_clk_source dispc_clk_src, dsi_clk_src;
int dsi_module = dsi->module_id;
@ -1459,7 +1416,7 @@ static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s)
dsi_clk_src = dss_get_dsi_clk_source(dsi->dss, dsi_module);
if (dsi_runtime_get(dsi))
return;
return 0;
seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
@ -1503,23 +1460,14 @@ static void dsi_dump_dsi_clocks(struct dsi_data *dsi, struct seq_file *s)
seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);
dsi_runtime_put(dsi);
}
void dsi_dump_clocks(struct seq_file *s)
{
struct dsi_data *dsi;
int i;
for (i = 0; i < MAX_NUM_DSI; i++) {
dsi = dsi_get_dsi_from_id(i);
if (dsi)
dsi_dump_dsi_clocks(dsi, s);
}
return 0;
}
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
static void dsi_dump_dsi_irqs(struct dsi_data *dsi, struct seq_file *s)
static int dsi_dump_dsi_irqs(struct seq_file *s, void *p)
{
struct dsi_data *dsi = p;
unsigned long flags;
struct dsi_irq_stats stats;
@ -1603,33 +1551,20 @@ static void dsi_dump_dsi_irqs(struct dsi_data *dsi, struct seq_file *s)
PIS(ULPSACTIVENOT_ALL0);
PIS(ULPSACTIVENOT_ALL1);
#undef PIS
}
static int dsi1_dump_irqs(struct seq_file *s, void *p)
{
struct dsi_data *dsi = dsi_get_dsi_from_id(0);
dsi_dump_dsi_irqs(dsi, s);
return 0;
}
static int dsi2_dump_irqs(struct seq_file *s, void *p)
{
struct dsi_data *dsi = dsi_get_dsi_from_id(1);
dsi_dump_dsi_irqs(dsi, s);
return 0;
}
#endif
static void dsi_dump_dsi_regs(struct dsi_data *dsi, struct seq_file *s)
static int dsi_dump_dsi_regs(struct seq_file *s, void *p)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsi, r))
struct dsi_data *dsi = p;
if (dsi_runtime_get(dsi))
return;
return 0;
dsi_enable_scp_clk(dsi);
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsi, r))
DUMPREG(DSI_REVISION);
DUMPREG(DSI_SYSCONFIG);
DUMPREG(DSI_SYSSTATUS);
@ -1699,25 +1634,11 @@ static void dsi_dump_dsi_regs(struct dsi_data *dsi, struct seq_file *s)
DUMPREG(DSI_PLL_GO);
DUMPREG(DSI_PLL_CONFIGURATION1);
DUMPREG(DSI_PLL_CONFIGURATION2);
#undef DUMPREG
dsi_disable_scp_clk(dsi);
dsi_runtime_put(dsi);
#undef DUMPREG
}
static int dsi1_dump_regs(struct seq_file *s, void *p)
{
struct dsi_data *dsi = dsi_get_dsi_from_id(0);
dsi_dump_dsi_regs(dsi, s);
return 0;
}
static int dsi2_dump_regs(struct seq_file *s, void *p)
{
struct dsi_data *dsi = dsi_get_dsi_from_id(1);
dsi_dump_dsi_regs(dsi, s);
return 0;
}
@ -3344,7 +3265,7 @@ static void dsi_config_vp_num_line_buffers(struct dsi_data *dsi)
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
struct videomode *vm = &dsi->vm;
const struct videomode *vm = &dsi->vm;
/*
* Don't use line buffers if width is greater than the video
* port's line buffer size
@ -3473,7 +3394,7 @@ static void dsi_config_cmd_mode_interleaving(struct dsi_data *dsi)
int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
int tclk_trail, ths_exit, exiths_clk;
bool ddr_alwon;
struct videomode *vm = &dsi->vm;
const struct videomode *vm = &dsi->vm;
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int ndl = dsi->num_lanes_used - 1;
int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1;
@ -3723,7 +3644,7 @@ static void dsi_proto_timings(struct dsi_data *dsi)
int vbp = dsi->vm_timings.vbp;
int window_sync = dsi->vm_timings.window_sync;
bool hsync_end;
struct videomode *vm = &dsi->vm;
const struct videomode *vm = &dsi->vm;
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int tl, t_he, width_bytes;
@ -3980,8 +3901,6 @@ static void dsi_update_screen_dispc(struct dsi_data *dsi)
msecs_to_jiffies(250));
BUG_ON(r == 0);
dss_mgr_set_timings(&dsi->output, &dsi->vm);
dss_mgr_start_update(&dsi->output);
if (dsi->te_enabled) {
@ -4123,24 +4042,6 @@ static int dsi_display_init_dispc(struct dsi_data *dsi)
dsi->mgr_config.fifohandcheck = false;
}
/*
* override interlace, logic level and edge related parameters in
* videomode with default values
*/
dsi->vm.flags &= ~DISPLAY_FLAGS_INTERLACED;
dsi->vm.flags &= ~DISPLAY_FLAGS_HSYNC_LOW;
dsi->vm.flags |= DISPLAY_FLAGS_HSYNC_HIGH;
dsi->vm.flags &= ~DISPLAY_FLAGS_VSYNC_LOW;
dsi->vm.flags |= DISPLAY_FLAGS_VSYNC_HIGH;
dsi->vm.flags &= ~DISPLAY_FLAGS_PIXDATA_NEGEDGE;
dsi->vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
dsi->vm.flags &= ~DISPLAY_FLAGS_DE_LOW;
dsi->vm.flags |= DISPLAY_FLAGS_DE_HIGH;
dsi->vm.flags &= ~DISPLAY_FLAGS_SYNC_POSEDGE;
dsi->vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
dss_mgr_set_timings(&dsi->output, &dsi->vm);
r = dsi_configure_dispc_clocks(dsi);
if (r)
goto err1;
@ -4840,6 +4741,19 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
dsi->user_dispc_cinfo = ctx.dispc_cinfo;
dsi->vm = ctx.vm;
/*
* override interlace, logic level and edge related parameters in
* videomode with default values
*/
dsi->vm.flags &= ~DISPLAY_FLAGS_INTERLACED;
dsi->vm.flags &= ~DISPLAY_FLAGS_HSYNC_LOW;
dsi->vm.flags |= DISPLAY_FLAGS_HSYNC_HIGH;
dsi->vm.flags &= ~DISPLAY_FLAGS_VSYNC_LOW;
dsi->vm.flags |= DISPLAY_FLAGS_VSYNC_HIGH;
dss_mgr_set_timings(&dsi->output, &dsi->vm);
dsi->vm_timings = ctx.dsi_vm;
mutex_unlock(&dsi->lock);
@ -4960,163 +4874,71 @@ static int dsi_get_clocks(struct dsi_data *dsi)
return 0;
}
static int dsi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int dsi_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct dsi_data *dsi = to_dsi_data(dssdev);
int r;
r = dsi_regulator_init(dsi);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
r = dss_mgr_connect(&dsi->output, dssdev);
if (r)
return r;
r = omapdss_output_set_device(dssdev, dst);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_mgr_disconnect(&dsi->output, dssdev);
return r;
}
dst->dispc_channel_connected = true;
return 0;
}
static void dsi_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void dsi_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct dsi_data *dsi = to_dsi_data(dssdev);
dst->dispc_channel_connected = false;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
omapdss_output_unset_device(dssdev);
dss_mgr_disconnect(&dsi->output, dssdev);
omapdss_device_disconnect(dst, dst->next);
}
static const struct omapdss_dsi_ops dsi_ops = {
static const struct omap_dss_device_ops dsi_ops = {
.connect = dsi_connect,
.disconnect = dsi_disconnect,
.bus_lock = dsi_bus_lock,
.bus_unlock = dsi_bus_unlock,
.enable = dsi_display_enable,
.disable = dsi_display_disable,
.enable_hs = dsi_vc_enable_hs,
.dsi = {
.bus_lock = dsi_bus_lock,
.bus_unlock = dsi_bus_unlock,
.configure_pins = dsi_configure_pins,
.set_config = dsi_set_config,
.disable = dsi_display_disable,
.enable_video_output = dsi_enable_video_output,
.disable_video_output = dsi_disable_video_output,
.enable_hs = dsi_vc_enable_hs,
.update = dsi_update,
.configure_pins = dsi_configure_pins,
.set_config = dsi_set_config,
.enable_te = dsi_enable_te,
.enable_video_output = dsi_enable_video_output,
.disable_video_output = dsi_disable_video_output,
.request_vc = dsi_request_vc,
.set_vc_id = dsi_set_vc_id,
.release_vc = dsi_release_vc,
.update = dsi_update,
.dcs_write = dsi_vc_dcs_write,
.dcs_write_nosync = dsi_vc_dcs_write_nosync,
.dcs_read = dsi_vc_dcs_read,
.enable_te = dsi_enable_te,
.gen_write = dsi_vc_generic_write,
.gen_write_nosync = dsi_vc_generic_write_nosync,
.gen_read = dsi_vc_generic_read,
.request_vc = dsi_request_vc,
.set_vc_id = dsi_set_vc_id,
.release_vc = dsi_release_vc,
.bta_sync = dsi_vc_send_bta_sync,
.dcs_write = dsi_vc_dcs_write,
.dcs_write_nosync = dsi_vc_dcs_write_nosync,
.dcs_read = dsi_vc_dcs_read,
.set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
.gen_write = dsi_vc_generic_write,
.gen_write_nosync = dsi_vc_generic_write_nosync,
.gen_read = dsi_vc_generic_read,
.bta_sync = dsi_vc_send_bta_sync,
.set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
},
};
static void dsi_init_output(struct dsi_data *dsi)
{
struct omap_dss_device *out = &dsi->output;
out->dev = dsi->dev;
out->id = dsi->module_id == 0 ?
OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
out->output_type = OMAP_DISPLAY_TYPE_DSI;
out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
out->dispc_channel = dsi_get_channel(dsi);
out->ops.dsi = &dsi_ops;
out->owner = THIS_MODULE;
omapdss_register_output(out);
}
static void dsi_uninit_output(struct dsi_data *dsi)
{
struct omap_dss_device *out = &dsi->output;
omapdss_unregister_output(out);
}
static int dsi_probe_of(struct dsi_data *dsi)
{
struct device_node *node = dsi->dev->of_node;
struct property *prop;
u32 lane_arr[10];
int len, num_pins;
int r, i;
struct device_node *ep;
struct omap_dsi_pin_config pin_cfg;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
if (!ep)
return 0;
prop = of_find_property(ep, "lanes", &len);
if (prop == NULL) {
dev_err(dsi->dev, "failed to find lane data\n");
r = -EINVAL;
goto err;
}
num_pins = len / sizeof(u32);
if (num_pins < 4 || num_pins % 2 != 0 ||
num_pins > dsi->num_lanes_supported * 2) {
dev_err(dsi->dev, "bad number of lanes\n");
r = -EINVAL;
goto err;
}
r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
if (r) {
dev_err(dsi->dev, "failed to read lane data\n");
goto err;
}
pin_cfg.num_pins = num_pins;
for (i = 0; i < num_pins; ++i)
pin_cfg.pins[i] = (int)lane_arr[i];
r = dsi_configure_pins(&dsi->output, &pin_cfg);
if (r) {
dev_err(dsi->dev, "failed to configure pins");
goto err;
}
of_node_put(ep);
return 0;
err:
of_node_put(ep);
return r;
}
/* -----------------------------------------------------------------------------
* PLL
*/
static const struct dss_pll_ops dsi_pll_ops = {
.enable = dsi_pll_enable,
@ -5231,7 +5053,175 @@ static int dsi_init_pll_data(struct dss_device *dss, struct dsi_data *dsi)
return 0;
}
/* DSI1 HW IP initialisation */
/* -----------------------------------------------------------------------------
* Component Bind & Unbind
*/
static int dsi_bind(struct device *dev, struct device *master, void *data)
{
struct dss_device *dss = dss_get_device(master);
struct dsi_data *dsi = dev_get_drvdata(dev);
char name[10];
u32 rev;
int r;
dsi->dss = dss;
dsi_init_pll_data(dss, dsi);
r = dsi_runtime_get(dsi);
if (r)
return r;
rev = dsi_read_reg(dsi, DSI_REVISION);
dev_dbg(dev, "OMAP DSI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
dsi->line_buffer_size = dsi_get_line_buf_size(dsi);
dsi_runtime_put(dsi);
snprintf(name, sizeof(name), "dsi%u_regs", dsi->module_id + 1);
dsi->debugfs.regs = dss_debugfs_create_file(dss, name,
dsi_dump_dsi_regs, &dsi);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
snprintf(name, sizeof(name), "dsi%u_irqs", dsi->module_id + 1);
dsi->debugfs.irqs = dss_debugfs_create_file(dss, name,
dsi_dump_dsi_irqs, &dsi);
#endif
snprintf(name, sizeof(name), "dsi%u_clks", dsi->module_id + 1);
dsi->debugfs.clks = dss_debugfs_create_file(dss, name,
dsi_dump_dsi_clocks, &dsi);
return 0;
}
static void dsi_unbind(struct device *dev, struct device *master, void *data)
{
struct dsi_data *dsi = dev_get_drvdata(dev);
dss_debugfs_remove_file(dsi->debugfs.clks);
dss_debugfs_remove_file(dsi->debugfs.irqs);
dss_debugfs_remove_file(dsi->debugfs.regs);
of_platform_depopulate(dev);
WARN_ON(dsi->scp_clk_refcount > 0);
dss_pll_unregister(&dsi->pll);
}
static const struct component_ops dsi_component_ops = {
.bind = dsi_bind,
.unbind = dsi_unbind,
};
/* -----------------------------------------------------------------------------
* Probe & Remove, Suspend & Resume
*/
static int dsi_init_output(struct dsi_data *dsi)
{
struct omap_dss_device *out = &dsi->output;
int r;
out->dev = dsi->dev;
out->id = dsi->module_id == 0 ?
OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
out->output_type = OMAP_DISPLAY_TYPE_DSI;
out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
out->dispc_channel = dsi_get_channel(dsi);
out->ops = &dsi_ops;
out->owner = THIS_MODULE;
out->of_ports = BIT(0);
out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE
| DRM_BUS_FLAG_DE_HIGH
| DRM_BUS_FLAG_SYNC_NEGEDGE;
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
}
r = omapdss_output_validate(out);
if (r) {
omapdss_device_put(out->next);
out->next = NULL;
return r;
}
omapdss_device_register(out);
return 0;
}
static void dsi_uninit_output(struct dsi_data *dsi)
{
struct omap_dss_device *out = &dsi->output;
if (out->next)
omapdss_device_put(out->next);
omapdss_device_unregister(out);
}
static int dsi_probe_of(struct dsi_data *dsi)
{
struct device_node *node = dsi->dev->of_node;
struct property *prop;
u32 lane_arr[10];
int len, num_pins;
int r, i;
struct device_node *ep;
struct omap_dsi_pin_config pin_cfg;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
if (!ep)
return 0;
prop = of_find_property(ep, "lanes", &len);
if (prop == NULL) {
dev_err(dsi->dev, "failed to find lane data\n");
r = -EINVAL;
goto err;
}
num_pins = len / sizeof(u32);
if (num_pins < 4 || num_pins % 2 != 0 ||
num_pins > dsi->num_lanes_supported * 2) {
dev_err(dsi->dev, "bad number of lanes\n");
r = -EINVAL;
goto err;
}
r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
if (r) {
dev_err(dsi->dev, "failed to read lane data\n");
goto err;
}
pin_cfg.num_pins = num_pins;
for (i = 0; i < num_pins; ++i)
pin_cfg.pins[i] = (int)lane_arr[i];
r = dsi_configure_pins(&dsi->output, &pin_cfg);
if (r) {
dev_err(dsi->dev, "failed to configure pins");
goto err;
}
of_node_put(ep);
return 0;
err:
of_node_put(ep);
return r;
}
static const struct dsi_of_data dsi_of_data_omap34xx = {
.model = DSI_MODEL_OMAP3,
.pll_hw = &dss_omap3_dsi_pll_hw,
@ -5297,23 +5287,21 @@ static const struct soc_device_attribute dsi_soc_devices[] = {
{ /* sentinel */ }
};
static int dsi_bind(struct device *dev, struct device *master, void *data)
static int dsi_probe(struct platform_device *pdev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dss_device *dss = dss_get_device(master);
const struct soc_device_attribute *soc;
const struct dsi_module_id_data *d;
u32 rev;
int r, i;
struct device *dev = &pdev->dev;
struct dsi_data *dsi;
struct resource *dsi_mem;
struct resource *res;
unsigned int i;
int r;
dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
if (!dsi)
return -ENOMEM;
dsi->dss = dss;
dsi->dev = dev;
dev_set_drvdata(dev, dsi);
@ -5364,6 +5352,13 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
return r;
}
dsi->vdds_dsi_reg = devm_regulator_get(dev, "vdd");
if (IS_ERR(dsi->vdds_dsi_reg)) {
if (PTR_ERR(dsi->vdds_dsi_reg) != -EPROBE_DEFER)
DSSERR("can't get DSI VDD regulator\n");
return PTR_ERR(dsi->vdds_dsi_reg);
}
soc = soc_device_match(dsi_soc_devices);
if (soc)
dsi->data = soc->data;
@ -5410,18 +5405,8 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
if (r)
return r;
dsi_init_pll_data(dss, dsi);
pm_runtime_enable(dev);
r = dsi_runtime_get(dsi);
if (r)
goto err_runtime_get;
rev = dsi_read_reg(dsi, DSI_REVISION);
dev_dbg(dev, "OMAP DSI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
/* DSI on OMAP3 doesn't have register DSI_GNQ, set number
* of data to 3 by default */
if (dsi->data->quirks & DSI_QUIRK_GNQ)
@ -5430,88 +5415,48 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
else
dsi->num_lanes_supported = 3;
dsi->line_buffer_size = dsi_get_line_buf_size(dsi);
dsi_init_output(dsi);
r = dsi_init_output(dsi);
if (r)
goto err_pm_disable;
r = dsi_probe_of(dsi);
if (r) {
DSSERR("Invalid DSI DT data\n");
goto err_probe_of;
goto err_uninit_output;
}
r = of_platform_populate(dev->of_node, NULL, NULL, dev);
if (r)
DSSERR("Failed to populate DSI child devices: %d\n", r);
dsi_runtime_put(dsi);
if (dsi->module_id == 0)
dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi1_regs",
dsi1_dump_regs,
&dsi);
else
dsi->debugfs.regs = dss_debugfs_create_file(dss, "dsi2_regs",
dsi2_dump_regs,
&dsi);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
if (dsi->module_id == 0)
dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi1_irqs",
dsi1_dump_irqs,
&dsi);
else
dsi->debugfs.irqs = dss_debugfs_create_file(dss, "dsi2_irqs",
dsi2_dump_irqs,
&dsi);
#endif
r = component_add(&pdev->dev, &dsi_component_ops);
if (r)
goto err_uninit_output;
return 0;
err_probe_of:
err_uninit_output:
dsi_uninit_output(dsi);
dsi_runtime_put(dsi);
err_runtime_get:
err_pm_disable:
pm_runtime_disable(dev);
return r;
}
static void dsi_unbind(struct device *dev, struct device *master, void *data)
static int dsi_remove(struct platform_device *pdev)
{
struct dsi_data *dsi = dev_get_drvdata(dev);
struct dsi_data *dsi = platform_get_drvdata(pdev);
dss_debugfs_remove_file(dsi->debugfs.irqs);
dss_debugfs_remove_file(dsi->debugfs.regs);
of_platform_depopulate(dev);
WARN_ON(dsi->scp_clk_refcount > 0);
dss_pll_unregister(&dsi->pll);
component_del(&pdev->dev, &dsi_component_ops);
dsi_uninit_output(dsi);
pm_runtime_disable(dev);
pm_runtime_disable(&pdev->dev);
if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
regulator_disable(dsi->vdds_dsi_reg);
dsi->vdds_dsi_enabled = false;
}
}
static const struct component_ops dsi_component_ops = {
.bind = dsi_bind,
.unbind = dsi_unbind,
};
static int dsi_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &dsi_component_ops);
}
static int dsi_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &dsi_component_ops);
return 0;
}

View file

@ -21,7 +21,8 @@
#include "omapdss.h"
struct device_node *dss_of_port_get_parent_device(struct device_node *port)
static struct device_node *
dss_of_port_get_parent_device(struct device_node *port)
{
struct device_node *np;
int i;
@ -45,41 +46,37 @@ struct device_node *dss_of_port_get_parent_device(struct device_node *port)
return NULL;
}
u32 dss_of_port_get_port_number(struct device_node *port)
{
int r;
u32 reg;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
return reg;
}
struct omap_dss_device *
omapdss_of_find_source_for_first_ep(struct device_node *node)
omapdss_of_find_connected_device(struct device_node *node, unsigned int port)
{
struct device_node *ep;
struct device_node *src_node;
struct device_node *src_port;
struct device_node *ep;
struct omap_dss_device *src;
u32 port_number = 0;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
/* Get the endpoint... */
ep = of_graph_get_endpoint_by_regs(node, port, 0);
if (!ep)
return ERR_PTR(-EINVAL);
return NULL;
/* ... and its remote port... */
src_port = of_graph_get_remote_port(ep);
if (!src_port) {
of_node_put(ep);
return ERR_PTR(-EINVAL);
}
of_node_put(ep);
if (!src_port)
return NULL;
src = omap_dss_find_output_by_port_node(src_port);
/* ... and the remote port's number and parent... */
of_property_read_u32(src_port, "reg", &port_number);
src_node = dss_of_port_get_parent_device(src_port);
of_node_put(src_port);
if (!src_node)
return ERR_PTR(-EINVAL);
/* ... and finally the connected device. */
src = omapdss_find_device_by_port(src_node, port_number);
of_node_put(src_node);
return src ? src : ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device);

View file

@ -394,9 +394,6 @@ static int dss_debug_dump_clocks(struct seq_file *s, void *p)
dss_dump_clocks(dss, s);
dispc_dump_clocks(dss->dispc, s);
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_dump_clocks(s);
#endif
return 0;
}
@ -681,12 +678,6 @@ unsigned long dss_get_max_fck_rate(struct dss_device *dss)
return dss->feat->fck_freq_max;
}
enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss,
enum omap_channel channel)
{
return dss->feat->outputs[channel];
}
static int dss_setup_default_clock(struct dss_device *dss)
{
unsigned long max_dss_fck, prate;
@ -1183,7 +1174,8 @@ static int dss_init_ports(struct dss_device *dss)
struct platform_device *pdev = dss->pdev;
struct device_node *parent = pdev->dev.of_node;
struct device_node *port;
int i;
unsigned int i;
int r;
for (i = 0; i < dss->feat->num_ports; i++) {
port = of_graph_get_port_by_id(parent, i);
@ -1192,11 +1184,17 @@ static int dss_init_ports(struct dss_device *dss)
switch (dss->feat->ports[i]) {
case OMAP_DISPLAY_TYPE_DPI:
dpi_init_port(dss, pdev, port, dss->feat->model);
r = dpi_init_port(dss, pdev, port, dss->feat->model);
if (r)
return r;
break;
case OMAP_DISPLAY_TYPE_SDI:
sdi_init_port(dss, pdev, port);
r = sdi_init_port(dss, pdev, port);
if (r)
return r;
break;
default:
break;
}
@ -1315,6 +1313,7 @@ static const struct soc_device_attribute dss_soc_devices[] = {
static int dss_bind(struct device *dev)
{
struct dss_device *dss = dev_get_drvdata(dev);
struct platform_device *drm_pdev;
int r;
r = component_bind_all(dev, NULL);
@ -1323,14 +1322,25 @@ static int dss_bind(struct device *dev)
pm_set_vt_switch(0);
omapdss_gather_components(dev);
omapdss_set_dss(dss);
drm_pdev = platform_device_register_simple("omapdrm", 0, NULL, 0);
if (IS_ERR(drm_pdev)) {
component_unbind_all(dev, NULL);
return PTR_ERR(drm_pdev);
}
dss->drm_pdev = drm_pdev;
return 0;
}
static void dss_unbind(struct device *dev)
{
struct dss_device *dss = dev_get_drvdata(dev);
platform_device_unregister(dss->drm_pdev);
omapdss_set_dss(NULL);
component_unbind_all(dev, NULL);
@ -1474,6 +1484,8 @@ static int dss_probe(struct platform_device *pdev)
dss);
/* Add all the child devices as components. */
omapdss_gather_components(&pdev->dev);
device_for_each_child(&pdev->dev, &match, dss_add_child_component);
r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
@ -1539,12 +1551,9 @@ static void dss_shutdown(struct platform_device *pdev)
DSSDBG("shutdown\n");
for_each_dss_dev(dssdev) {
if (!dssdev->driver)
continue;
for_each_dss_display(dssdev) {
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
dssdev->driver->disable(dssdev);
dssdev->ops->disable(dssdev);
}
}

View file

@ -238,6 +238,8 @@ struct dss_device {
struct regmap *syscon_pll_ctrl;
u32 syscon_pll_ctrl_offset;
struct platform_device *drm_pdev;
struct clk *parent_clk;
struct clk *dss_clk;
unsigned long dss_clk_rate;
@ -267,6 +269,8 @@ struct dss_device {
struct dispc_device *dispc;
const struct dispc_ops *dispc_ops;
const struct dss_mgr_ops *mgr_ops;
struct omap_drm_private *mgr_ops_priv;
};
/* core */
@ -313,8 +317,6 @@ void dss_runtime_put(struct dss_device *dss);
unsigned long dss_get_dispc_clk_rate(struct dss_device *dss);
unsigned long dss_get_max_fck_rate(struct dss_device *dss);
enum omap_dss_output_id dss_get_supported_outputs(struct dss_device *dss,
enum omap_channel channel);
int dss_dpi_select_source(struct dss_device *dss, int port,
enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(struct dss_device *dss,
@ -374,8 +376,6 @@ static inline void sdi_uninit_port(struct device_node *port)
#ifdef CONFIG_OMAP2_DSS_DSI
void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void);
#endif
@ -417,9 +417,6 @@ bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq,
unsigned long pck_min, unsigned long pck_max,
dispc_div_calc_func func, void *data);
bool dispc_mgr_timings_ok(struct dispc_device *dispc,
enum omap_channel channel,
const struct videomode *vm);
int dispc_calc_clock_rates(struct dispc_device *dispc,
unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);

View file

@ -313,13 +313,13 @@ void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask);
int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val);
int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val);
void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
struct hdmi_video_format *video_fmt);
const struct hdmi_video_format *video_fmt);
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
struct videomode *vm);
const struct videomode *vm);
void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
struct videomode *vm);
const struct videomode *vm);
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
struct videomode *vm, struct hdmi_config *param);
struct videomode *vm, const struct hdmi_config *param);
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp,
unsigned int version);
phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);

View file

@ -108,26 +108,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static int hdmi_init_regulator(struct omap_hdmi *hdmi)
{
struct regulator *reg;
if (hdmi->vdda_reg != NULL)
return 0;
reg = devm_regulator_get(&hdmi->pdev->dev, "vdda");
if (IS_ERR(reg)) {
if (PTR_ERR(reg) != -EPROBE_DEFER)
DSSERR("can't get VDDA regulator\n");
return PTR_ERR(reg);
}
hdmi->vdda_reg = reg;
return 0;
}
static int hdmi_power_on_core(struct omap_hdmi *hdmi)
{
int r;
@ -174,7 +154,7 @@ static void hdmi_power_off_core(struct omap_hdmi *hdmi)
static int hdmi_power_on_full(struct omap_hdmi *hdmi)
{
int r;
struct videomode *vm;
const struct videomode *vm;
struct hdmi_wp_data *wp = &hdmi->wp;
struct dss_pll_clock_info hdmi_cinfo = { 0 };
unsigned int pc;
@ -227,9 +207,6 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi)
hdmi4_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
/* tv size */
dss_mgr_set_timings(&hdmi->output, vm);
r = dss_mgr_enable(&hdmi->output);
if (r)
goto err_mgr_enable;
@ -271,19 +248,8 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
hdmi_power_off_core(hdmi);
}
static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
return -EINVAL;
return 0;
}
static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
struct videomode *vm)
static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
const struct videomode *vm)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
@ -296,14 +262,6 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
mutex_unlock(&hdmi->lock);
}
static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
*vm = hdmi->cfg.vm;
}
static int hdmi_dump_regs(struct seq_file *s, void *p)
{
struct omap_hdmi *hdmi = s->private;
@ -456,44 +414,25 @@ void hdmi4_core_disable(struct hdmi_core_data *core)
mutex_unlock(&hdmi->lock);
}
static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int hdmi_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
int r;
r = hdmi_init_regulator(hdmi);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
r = dss_mgr_connect(&hdmi->output, dssdev);
if (r)
return r;
r = omapdss_output_set_device(dssdev, dst);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dst->name);
dss_mgr_disconnect(&hdmi->output, dssdev);
return r;
}
dst->dispc_channel_connected = true;
return 0;
}
static void hdmi_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void hdmi_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
dst->dispc_channel_connected = false;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
omapdss_output_unset_device(dssdev);
dss_mgr_disconnect(&hdmi->output, dssdev);
omapdss_device_disconnect(dst, dst->next);
}
static int hdmi_read_edid(struct omap_dss_device *dssdev,
@ -548,69 +487,28 @@ static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
return 0;
}
static const struct omapdss_hdmi_ops hdmi_ops = {
static const struct omap_dss_device_ops hdmi_ops = {
.connect = hdmi_connect,
.disconnect = hdmi_disconnect,
.enable = hdmi_display_enable,
.disable = hdmi_display_disable,
.check_timings = hdmi_display_check_timing,
.set_timings = hdmi_display_set_timing,
.get_timings = hdmi_display_get_timings,
.set_timings = hdmi_display_set_timings,
.read_edid = hdmi_read_edid,
.lost_hotplug = hdmi_lost_hotplug,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
.hdmi = {
.lost_hotplug = hdmi_lost_hotplug,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
},
};
static void hdmi_init_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
/* -----------------------------------------------------------------------------
* Audio Callbacks
*/
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->ops.hdmi = &hdmi_ops;
out->owner = THIS_MODULE;
omapdss_register_output(out);
}
static void hdmi_uninit_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
omapdss_unregister_output(out);
}
static int hdmi_probe_of(struct omap_hdmi *hdmi)
{
struct platform_device *pdev = hdmi->pdev;
struct device_node *node = pdev->dev.of_node;
struct device_node *ep;
int r;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
if (!ep)
return 0;
r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
if (r)
goto err;
of_node_put(ep);
return 0;
err:
of_node_put(ep);
return r;
}
/* Audio callbacks */
static int hdmi_audio_startup(struct device *dev,
void (*abort_cb)(struct device *dev))
{
@ -725,75 +623,30 @@ static int hdmi_audio_register(struct omap_hdmi *hdmi)
return 0;
}
/* HDMI HW IP initialisation */
/* -----------------------------------------------------------------------------
* Component Bind & Unbind
*/
static int hdmi4_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct dss_device *dss = dss_get_device(master);
struct omap_hdmi *hdmi;
struct omap_hdmi *hdmi = dev_get_drvdata(dev);
int r;
int irq;
hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
hdmi->pdev = pdev;
hdmi->dss = dss;
dev_set_drvdata(&pdev->dev, hdmi);
mutex_init(&hdmi->lock);
spin_lock_init(&hdmi->audio_playing_lock);
r = hdmi_probe_of(hdmi);
r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
if (r)
goto err_free;
return r;
r = hdmi_wp_init(pdev, &hdmi->wp, 4);
r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
if (r)
goto err_free;
r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp);
if (r)
goto err_free;
r = hdmi_phy_init(pdev, &hdmi->phy, 4);
if (r)
goto err_pll;
r = hdmi4_core_init(pdev, &hdmi->core);
if (r)
goto err_pll;
r = hdmi4_cec_init(pdev, &hdmi->core, &hdmi->wp);
if (r)
goto err_pll;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
r = -ENODEV;
goto err_pll;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
NULL, hdmi_irq_handler,
IRQF_ONESHOT, "OMAP HDMI", hdmi);
if (r) {
DSSERR("HDMI IRQ request failed\n");
goto err_pll;
}
pm_runtime_enable(&pdev->dev);
hdmi_init_output(hdmi);
goto err_pll_uninit;
r = hdmi_audio_register(hdmi);
if (r) {
DSSERR("Registering HDMI audio failed\n");
hdmi_uninit_output(hdmi);
pm_runtime_disable(&pdev->dev);
return r;
goto err_cec_uninit;
}
hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
@ -801,10 +654,10 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
return 0;
err_pll:
err_cec_uninit:
hdmi4_cec_uninit(&hdmi->core);
err_pll_uninit:
hdmi_pll_uninit(&hdmi->pll);
err_free:
kfree(hdmi);
return r;
}
@ -817,15 +670,8 @@ static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
if (hdmi->audio_pdev)
platform_device_unregister(hdmi->audio_pdev);
hdmi_uninit_output(hdmi);
hdmi4_cec_uninit(&hdmi->core);
hdmi_pll_uninit(&hdmi->pll);
pm_runtime_disable(dev);
kfree(hdmi);
}
static const struct component_ops hdmi4_component_ops = {
@ -833,14 +679,157 @@ static const struct component_ops hdmi4_component_ops = {
.unbind = hdmi4_unbind,
};
/* -----------------------------------------------------------------------------
* Probe & Remove, Suspend & Resume
*/
static int hdmi4_init_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
int r;
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->ops = &hdmi_ops;
out->owner = THIS_MODULE;
out->of_ports = BIT(0);
out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
}
r = omapdss_output_validate(out);
if (r) {
omapdss_device_put(out->next);
out->next = NULL;
return r;
}
omapdss_device_register(out);
return 0;
}
static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
if (out->next)
omapdss_device_put(out->next);
omapdss_device_unregister(out);
}
static int hdmi4_probe_of(struct omap_hdmi *hdmi)
{
struct platform_device *pdev = hdmi->pdev;
struct device_node *node = pdev->dev.of_node;
struct device_node *ep;
int r;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
if (!ep)
return 0;
r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
of_node_put(ep);
return r;
}
static int hdmi4_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &hdmi4_component_ops);
struct omap_hdmi *hdmi;
int irq;
int r;
hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
hdmi->pdev = pdev;
dev_set_drvdata(&pdev->dev, hdmi);
mutex_init(&hdmi->lock);
spin_lock_init(&hdmi->audio_playing_lock);
r = hdmi4_probe_of(hdmi);
if (r)
goto err_free;
r = hdmi_wp_init(pdev, &hdmi->wp, 4);
if (r)
goto err_free;
r = hdmi_phy_init(pdev, &hdmi->phy, 4);
if (r)
goto err_free;
r = hdmi4_core_init(pdev, &hdmi->core);
if (r)
goto err_free;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
r = -ENODEV;
goto err_free;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
NULL, hdmi_irq_handler,
IRQF_ONESHOT, "OMAP HDMI", hdmi);
if (r) {
DSSERR("HDMI IRQ request failed\n");
goto err_free;
}
hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
if (IS_ERR(hdmi->vdda_reg)) {
r = PTR_ERR(hdmi->vdda_reg);
if (r != -EPROBE_DEFER)
DSSERR("can't get VDDA regulator\n");
goto err_free;
}
pm_runtime_enable(&pdev->dev);
r = hdmi4_init_output(hdmi);
if (r)
goto err_pm_disable;
r = component_add(&pdev->dev, &hdmi4_component_ops);
if (r)
goto err_uninit_output;
return 0;
err_uninit_output:
hdmi4_uninit_output(hdmi);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
err_free:
kfree(hdmi);
return r;
}
static int hdmi4_remove(struct platform_device *pdev)
{
struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
component_del(&pdev->dev, &hdmi4_component_ops);
hdmi4_uninit_output(hdmi);
pm_runtime_disable(&pdev->dev);
kfree(hdmi);
return 0;
}

View file

@ -117,24 +117,6 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static int hdmi_init_regulator(struct omap_hdmi *hdmi)
{
struct regulator *reg;
if (hdmi->vdda_reg != NULL)
return 0;
reg = devm_regulator_get(&hdmi->pdev->dev, "vdda");
if (IS_ERR(reg)) {
DSSERR("can't get VDDA regulator\n");
return PTR_ERR(reg);
}
hdmi->vdda_reg = reg;
return 0;
}
static int hdmi_power_on_core(struct omap_hdmi *hdmi)
{
int r;
@ -171,7 +153,7 @@ static void hdmi_power_off_core(struct omap_hdmi *hdmi)
static int hdmi_power_on_full(struct omap_hdmi *hdmi)
{
int r;
struct videomode *vm;
const struct videomode *vm;
struct dss_pll_clock_info hdmi_cinfo = { 0 };
unsigned int pc;
@ -224,9 +206,6 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi)
hdmi5_configure(&hdmi->core, &hdmi->wp, &hdmi->cfg);
/* tv size */
dss_mgr_set_timings(&hdmi->output, vm);
r = dss_mgr_enable(&hdmi->output);
if (r)
goto err_mgr_enable;
@ -268,19 +247,8 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
hdmi_power_off_core(hdmi);
}
static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
if (!dispc_mgr_timings_ok(hdmi->dss->dispc, dssdev->dispc_channel, vm))
return -EINVAL;
return 0;
}
static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
struct videomode *vm)
static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
const struct videomode *vm)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
@ -293,14 +261,6 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
mutex_unlock(&hdmi->lock);
}
static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
*vm = hdmi->cfg.vm;
}
static int hdmi_dump_regs(struct seq_file *s, void *p)
{
struct omap_hdmi *hdmi = s->private;
@ -459,44 +419,25 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi)
mutex_unlock(&hdmi->lock);
}
static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int hdmi_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
int r;
r = hdmi_init_regulator(hdmi);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
r = dss_mgr_connect(&hdmi->output, dssdev);
if (r)
return r;
r = omapdss_output_set_device(dssdev, dst);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dst->name);
dss_mgr_disconnect(&hdmi->output, dssdev);
return r;
}
dst->dispc_channel_connected = true;
return 0;
}
static void hdmi_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void hdmi_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
dst->dispc_channel_connected = false;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
omapdss_output_unset_device(dssdev);
dss_mgr_disconnect(&hdmi->output, dssdev);
omapdss_device_disconnect(dst, dst->next);
}
static int hdmi_read_edid(struct omap_dss_device *dssdev,
@ -540,68 +481,27 @@ static int hdmi_set_hdmi_mode(struct omap_dss_device *dssdev,
return 0;
}
static const struct omapdss_hdmi_ops hdmi_ops = {
static const struct omap_dss_device_ops hdmi_ops = {
.connect = hdmi_connect,
.disconnect = hdmi_disconnect,
.enable = hdmi_display_enable,
.disable = hdmi_display_disable,
.check_timings = hdmi_display_check_timing,
.set_timings = hdmi_display_set_timing,
.get_timings = hdmi_display_get_timings,
.set_timings = hdmi_display_set_timings,
.read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
.hdmi = {
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
},
};
static void hdmi_init_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
/* -----------------------------------------------------------------------------
* Audio Callbacks
*/
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->ops.hdmi = &hdmi_ops;
out->owner = THIS_MODULE;
omapdss_register_output(out);
}
static void hdmi_uninit_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
omapdss_unregister_output(out);
}
static int hdmi_probe_of(struct omap_hdmi *hdmi)
{
struct platform_device *pdev = hdmi->pdev;
struct device_node *node = pdev->dev.of_node;
struct device_node *ep;
int r;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
if (!ep)
return 0;
r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
if (r)
goto err;
of_node_put(ep);
return 0;
err:
of_node_put(ep);
return r;
}
/* Audio callbacks */
static int hdmi_audio_startup(struct device *dev,
void (*abort_cb)(struct device *dev))
{
@ -722,71 +622,26 @@ static int hdmi_audio_register(struct omap_hdmi *hdmi)
return 0;
}
/* HDMI HW IP initialisation */
/* -----------------------------------------------------------------------------
* Component Bind & Unbind
*/
static int hdmi5_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct dss_device *dss = dss_get_device(master);
struct omap_hdmi *hdmi;
struct omap_hdmi *hdmi = dev_get_drvdata(dev);
int r;
int irq;
hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
hdmi->pdev = pdev;
hdmi->dss = dss;
dev_set_drvdata(&pdev->dev, hdmi);
mutex_init(&hdmi->lock);
spin_lock_init(&hdmi->audio_playing_lock);
r = hdmi_probe_of(hdmi);
r = hdmi_pll_init(dss, hdmi->pdev, &hdmi->pll, &hdmi->wp);
if (r)
goto err_free;
r = hdmi_wp_init(pdev, &hdmi->wp, 5);
if (r)
goto err_free;
r = hdmi_pll_init(dss, pdev, &hdmi->pll, &hdmi->wp);
if (r)
goto err_free;
r = hdmi_phy_init(pdev, &hdmi->phy, 5);
if (r)
goto err_pll;
r = hdmi5_core_init(pdev, &hdmi->core);
if (r)
goto err_pll;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
r = -ENODEV;
goto err_pll;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
NULL, hdmi_irq_handler,
IRQF_ONESHOT, "OMAP HDMI", hdmi);
if (r) {
DSSERR("HDMI IRQ request failed\n");
goto err_pll;
}
pm_runtime_enable(&pdev->dev);
hdmi_init_output(hdmi);
return r;
r = hdmi_audio_register(hdmi);
if (r) {
DSSERR("Registering HDMI audio failed %d\n", r);
hdmi_uninit_output(hdmi);
pm_runtime_disable(&pdev->dev);
return r;
goto err_pll_uninit;
}
hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
@ -794,10 +649,8 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data)
return 0;
err_pll:
err_pll_uninit:
hdmi_pll_uninit(&hdmi->pll);
err_free:
kfree(hdmi);
return r;
}
@ -810,13 +663,7 @@ static void hdmi5_unbind(struct device *dev, struct device *master, void *data)
if (hdmi->audio_pdev)
platform_device_unregister(hdmi->audio_pdev);
hdmi_uninit_output(hdmi);
hdmi_pll_uninit(&hdmi->pll);
pm_runtime_disable(dev);
kfree(hdmi);
}
static const struct component_ops hdmi5_component_ops = {
@ -824,14 +671,157 @@ static const struct component_ops hdmi5_component_ops = {
.unbind = hdmi5_unbind,
};
/* -----------------------------------------------------------------------------
* Probe & Remove, Suspend & Resume
*/
static int hdmi5_init_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
int r;
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->ops = &hdmi_ops;
out->owner = THIS_MODULE;
out->of_ports = BIT(0);
out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
}
r = omapdss_output_validate(out);
if (r) {
omapdss_device_put(out->next);
out->next = NULL;
return r;
}
omapdss_device_register(out);
return 0;
}
static void hdmi5_uninit_output(struct omap_hdmi *hdmi)
{
struct omap_dss_device *out = &hdmi->output;
if (out->next)
omapdss_device_put(out->next);
omapdss_device_unregister(out);
}
static int hdmi5_probe_of(struct omap_hdmi *hdmi)
{
struct platform_device *pdev = hdmi->pdev;
struct device_node *node = pdev->dev.of_node;
struct device_node *ep;
int r;
ep = of_graph_get_endpoint_by_regs(node, 0, 0);
if (!ep)
return 0;
r = hdmi_parse_lanes_of(pdev, ep, &hdmi->phy);
of_node_put(ep);
return r;
}
static int hdmi5_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &hdmi5_component_ops);
struct omap_hdmi *hdmi;
int irq;
int r;
hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
hdmi->pdev = pdev;
dev_set_drvdata(&pdev->dev, hdmi);
mutex_init(&hdmi->lock);
spin_lock_init(&hdmi->audio_playing_lock);
r = hdmi5_probe_of(hdmi);
if (r)
goto err_free;
r = hdmi_wp_init(pdev, &hdmi->wp, 5);
if (r)
goto err_free;
r = hdmi_phy_init(pdev, &hdmi->phy, 5);
if (r)
goto err_free;
r = hdmi5_core_init(pdev, &hdmi->core);
if (r)
goto err_free;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
r = -ENODEV;
goto err_free;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
NULL, hdmi_irq_handler,
IRQF_ONESHOT, "OMAP HDMI", hdmi);
if (r) {
DSSERR("HDMI IRQ request failed\n");
goto err_free;
}
hdmi->vdda_reg = devm_regulator_get(&pdev->dev, "vdda");
if (IS_ERR(hdmi->vdda_reg)) {
r = PTR_ERR(hdmi->vdda_reg);
if (r != -EPROBE_DEFER)
DSSERR("can't get VDDA regulator\n");
goto err_free;
}
pm_runtime_enable(&pdev->dev);
r = hdmi5_init_output(hdmi);
if (r)
goto err_pm_disable;
r = component_add(&pdev->dev, &hdmi5_component_ops);
if (r)
goto err_uninit_output;
return 0;
err_uninit_output:
hdmi5_uninit_output(hdmi);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
err_free:
kfree(hdmi);
return r;
}
static int hdmi5_remove(struct platform_device *pdev)
{
struct omap_hdmi *hdmi = platform_get_drvdata(pdev);
component_del(&pdev->dev, &hdmi5_component_ops);
hdmi5_uninit_output(hdmi);
pm_runtime_disable(&pdev->dev);
kfree(hdmi);
return 0;
}

View file

@ -287,7 +287,7 @@ void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)
}
static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
struct hdmi_config *cfg)
const struct hdmi_config *cfg)
{
DSSDBG("hdmi_core_init\n");
@ -325,10 +325,10 @@ static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
/* DSS_HDMI_CORE_VIDEO_CONFIG */
static void hdmi_core_video_config(struct hdmi_core_data *core,
struct hdmi_core_vid_config *cfg)
const struct hdmi_core_vid_config *cfg)
{
void __iomem *base = core->base;
struct videomode *vm = &cfg->v_fc_config.vm;
const struct videomode *vm = &cfg->v_fc_config.vm;
unsigned char r = 0;
bool vsync_pol, hsync_pol;

View file

@ -131,7 +131,7 @@ void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
}
void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
struct hdmi_video_format *video_fmt)
const struct hdmi_video_format *video_fmt)
{
u32 l = 0;
@ -144,7 +144,7 @@ void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
}
void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
struct videomode *vm)
const struct videomode *vm)
{
u32 r;
bool vsync_inv, hsync_inv;
@ -164,7 +164,7 @@ void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
}
void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
struct videomode *vm)
const struct videomode *vm)
{
u32 timing_h = 0;
u32 timing_v = 0;
@ -193,7 +193,7 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
}
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
struct videomode *vm, struct hdmi_config *param)
struct videomode *vm, const struct hdmi_config *param)
{
DSSDBG("Enter hdmi_wp_video_init_format\n");

View file

@ -296,117 +296,14 @@ struct omap_dss_writeback_info {
u8 pre_mult_alpha;
};
struct omapdss_dpi_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
};
struct omapdss_sdi_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
};
struct omapdss_dvi_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
};
struct omapdss_atv_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
u32 (*get_wss)(struct omap_dss_device *dssdev);
};
struct omapdss_hdmi_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
void (*lost_hotplug)(struct omap_dss_device *dssdev);
bool (*detect)(struct omap_dss_device *dssdev);
int (*register_hpd_cb)(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data);
void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
void (*enable_hpd)(struct omap_dss_device *dssdev);
void (*disable_hpd)(struct omap_dss_device *dssdev);
int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
int (*set_infoframe)(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi);
};
struct omapdss_dsi_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes,
bool enter_ulps);
@ -457,53 +354,95 @@ struct omapdss_dsi_ops {
int channel, u16 plen);
};
struct omap_dss_device_ops {
int (*connect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
int (*enable)(struct omap_dss_device *dssdev);
void (*disable)(struct omap_dss_device *dssdev);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
const struct videomode *vm);
bool (*detect)(struct omap_dss_device *dssdev);
void (*register_hpd_cb)(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data);
void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
union {
const struct omapdss_hdmi_ops hdmi;
const struct omapdss_dsi_ops dsi;
};
};
/**
* enum omap_dss_device_ops_flag - Indicates which device ops are supported
* @OMAP_DSS_DEVICE_OP_DETECT: The device supports output connection detection
* @OMAP_DSS_DEVICE_OP_HPD: The device supports all hot-plug-related operations
* @OMAP_DSS_DEVICE_OP_EDID: The device supports readind EDID
*/
enum omap_dss_device_ops_flag {
OMAP_DSS_DEVICE_OP_DETECT = BIT(0),
OMAP_DSS_DEVICE_OP_HPD = BIT(1),
OMAP_DSS_DEVICE_OP_EDID = BIT(2),
};
enum omap_dss_device_type {
OMAP_DSS_DEVICE_TYPE_OUTPUT = (1 << 0),
OMAP_DSS_DEVICE_TYPE_DISPLAY = (1 << 1),
};
struct omap_dss_device {
struct kobject kobj;
struct device *dev;
struct module *owner;
struct list_head panel_list;
struct dss_device *dss;
struct omap_dss_device *src;
struct omap_dss_device *dst;
struct omap_dss_device *next;
/* alias in the form of "display%d" */
char alias[16];
struct list_head list;
unsigned int alias_id;
enum omap_display_type type;
/*
* DSS output type that this device generates (for DSS internal devices)
* or requires (for external encoders). Must be OMAP_DISPLAY_TYPE_NONE
* for display devices (connectors and panels) and to non-zero value for
* all other devices.
*/
enum omap_display_type output_type;
struct {
struct videomode vm;
enum omap_dss_dsi_pixel_format dsi_pix_fmt;
enum omap_dss_dsi_mode dsi_mode;
} panel;
const char *name;
struct omap_dss_driver *driver;
union {
const struct omapdss_dpi_ops *dpi;
const struct omapdss_sdi_ops *sdi;
const struct omapdss_dvi_ops *dvi;
const struct omapdss_hdmi_ops *hdmi;
const struct omapdss_atv_ops *atv;
const struct omapdss_dsi_ops *dsi;
} ops;
const struct omap_dss_driver *driver;
const struct omap_dss_device_ops *ops;
unsigned long ops_flags;
unsigned long bus_flags;
/* helper variable for driver suspend/resume */
bool activate_after_resume;
enum omap_display_caps caps;
struct omap_dss_device *src;
enum omap_dss_display_state state;
/* OMAP DSS output specific fields */
struct list_head list;
/* DISPC channel for this output */
enum omap_channel dispc_channel;
bool dispc_channel_connected;
@ -511,24 +450,11 @@ struct omap_dss_device {
/* output instance */
enum omap_dss_output_id id;
/* the port number in the DT node */
int port_num;
/* dynamic fields */
struct omap_dss_device *dst;
/* bitmask of port numbers in DT */
unsigned int of_ports;
};
struct omap_dss_driver {
int (*probe)(struct omap_dss_device *);
void (*remove)(struct omap_dss_device *);
int (*connect)(struct omap_dss_device *dssdev);
void (*disconnect)(struct omap_dss_device *dssdev);
int (*enable)(struct omap_dss_device *display);
void (*disable)(struct omap_dss_device *display);
int (*run_test)(struct omap_dss_device *display, int test);
int (*update)(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h);
int (*sync)(struct omap_dss_device *dssdev);
@ -536,42 +462,12 @@ struct omap_dss_driver {
int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
int (*get_te)(struct omap_dss_device *dssdev);
u8 (*get_rotate)(struct omap_dss_device *dssdev);
int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
bool (*get_mirror)(struct omap_dss_device *dssdev);
int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
int (*memory_read)(struct omap_dss_device *dssdev,
void *buf, size_t size,
u16 x, u16 y, u16 w, u16 h);
int (*check_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*set_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_timings)(struct omap_dss_device *dssdev,
struct videomode *vm);
void (*get_size)(struct omap_dss_device *dssdev,
unsigned int *width, unsigned int *height);
int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
u32 (*get_wss)(struct omap_dss_device *dssdev);
int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
bool (*detect)(struct omap_dss_device *dssdev);
int (*register_hpd_cb)(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data);
void (*unregister_hpd_cb)(struct omap_dss_device *dssdev);
void (*enable_hpd)(struct omap_dss_device *dssdev);
void (*disable_hpd)(struct omap_dss_device *dssdev);
int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi);
};
struct dss_device *omapdss_get_dss(void);
@ -581,27 +477,32 @@ static inline bool omapdss_is_initialized(void)
return !!omapdss_get_dss();
}
int omapdss_register_display(struct omap_dss_device *dssdev);
void omapdss_unregister_display(struct omap_dss_device *dssdev);
#define for_each_dss_display(d) \
while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL)
void omapdss_display_init(struct omap_dss_device *dssdev);
struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);
struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev);
void omap_dss_put_device(struct omap_dss_device *dssdev);
#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
void omapdss_device_register(struct omap_dss_device *dssdev);
void omapdss_device_unregister(struct omap_dss_device *dssdev);
struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev);
void omapdss_device_put(struct omap_dss_device *dssdev);
struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
unsigned int port);
struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
enum omap_dss_device_type type);
int omapdss_device_connect(struct dss_device *dss,
struct omap_dss_device *src,
struct omap_dss_device *dst);
void omapdss_device_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst);
int omap_dss_get_num_overlay_managers(void);
int omap_dss_get_num_overlays(void);
int omapdss_register_output(struct omap_dss_device *output);
void omapdss_unregister_output(struct omap_dss_device *output);
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id);
struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port);
int omapdss_output_set_device(struct omap_dss_device *out,
struct omap_dss_device *dssdev);
int omapdss_output_unset_device(struct omap_dss_device *out);
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev);
#define for_each_dss_output(d) \
while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_OUTPUT)) != NULL)
int omapdss_output_validate(struct omap_dss_device *out);
typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
@ -621,10 +522,7 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
}
struct omap_dss_device *
omapdss_of_find_source_for_first_ep(struct device_node *node);
struct device_node *dss_of_port_get_parent_device(struct device_node *port);
u32 dss_of_port_get_port_number(struct device_node *port);
omapdss_of_find_connected_device(struct device_node *node, unsigned int port);
enum dss_writeback_channel {
DSS_WB_LCD1_MGR = 0,
@ -638,13 +536,6 @@ enum dss_writeback_channel {
};
struct dss_mgr_ops {
int (*connect)(struct omap_drm_private *priv,
enum omap_channel channel,
struct omap_dss_device *dst);
void (*disconnect)(struct omap_drm_private *priv,
enum omap_channel channel,
struct omap_dss_device *dst);
void (*start_update)(struct omap_drm_private *priv,
enum omap_channel channel);
int (*enable)(struct omap_drm_private *priv,
@ -665,14 +556,11 @@ struct dss_mgr_ops {
void (*handler)(void *), void *data);
};
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops,
int dss_install_mgr_ops(struct dss_device *dss,
const struct dss_mgr_ops *mgr_ops,
struct omap_drm_private *priv);
void dss_uninstall_mgr_ops(void);
void dss_uninstall_mgr_ops(struct dss_device *dss);
int dss_mgr_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void dss_mgr_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst);
void dss_mgr_set_timings(struct omap_dss_device *dssdev,
const struct videomode *vm);
void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev,
@ -720,13 +608,14 @@ struct dispc_ops {
void (*mgr_set_lcd_config)(struct dispc_device *dispc,
enum omap_channel channel,
const struct dss_lcd_mgr_config *config);
int (*mgr_check_timings)(struct dispc_device *dispc,
enum omap_channel channel,
const struct videomode *vm);
void (*mgr_set_timings)(struct dispc_device *dispc,
enum omap_channel channel,
const struct videomode *vm);
void (*mgr_setup)(struct dispc_device *dispc, enum omap_channel channel,
const struct omap_overlay_manager_info *info);
enum omap_dss_output_id (*mgr_get_supported_outputs)(
struct dispc_device *dispc, enum omap_channel channel);
u32 (*mgr_gamma_size)(struct dispc_device *dispc,
enum omap_channel channel);
void (*mgr_set_gamma)(struct dispc_device *dispc,
@ -757,9 +646,6 @@ struct dispc_ops {
struct dispc_device *dispc_get_dispc(struct dss_device *dss);
const struct dispc_ops *dispc_get_ops(struct dss_device *dss);
bool omapdss_component_is_display(struct device_node *node);
bool omapdss_component_is_output(struct device_node *node);
bool omapdss_stack_is_ready(void);
void omapdss_gather_components(struct device *dev);

View file

@ -21,238 +21,96 @@
#include <linux/slab.h>
#include <linux/of.h>
#include "dss.h"
#include "omapdss.h"
static LIST_HEAD(output_list);
static DEFINE_MUTEX(output_lock);
int omapdss_output_set_device(struct omap_dss_device *out,
struct omap_dss_device *dssdev)
int omapdss_output_validate(struct omap_dss_device *out)
{
int r;
mutex_lock(&output_lock);
if (out->dst) {
dev_err(out->dev,
"output already has device %s connected to it\n",
out->dst->name);
r = -EINVAL;
goto err;
}
if (out->output_type != dssdev->type) {
if (out->next && out->output_type != out->next->type) {
dev_err(out->dev, "output type and display type don't match\n");
r = -EINVAL;
goto err;
return -EINVAL;
}
out->dst = dssdev;
dssdev->src = out;
mutex_unlock(&output_lock);
return 0;
err:
mutex_unlock(&output_lock);
return r;
}
EXPORT_SYMBOL(omapdss_output_set_device);
EXPORT_SYMBOL(omapdss_output_validate);
int omapdss_output_unset_device(struct omap_dss_device *out)
{
int r;
mutex_lock(&output_lock);
if (!out->dst) {
dev_err(out->dev,
"output doesn't have a device connected to it\n");
r = -EINVAL;
goto err;
}
if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) {
dev_err(out->dev,
"device %s is not disabled, cannot unset device\n",
out->dst->name);
r = -EINVAL;
goto err;
}
out->dst->src = NULL;
out->dst = NULL;
mutex_unlock(&output_lock);
return 0;
err:
mutex_unlock(&output_lock);
return r;
}
EXPORT_SYMBOL(omapdss_output_unset_device);
int omapdss_register_output(struct omap_dss_device *out)
{
list_add_tail(&out->list, &output_list);
return 0;
}
EXPORT_SYMBOL(omapdss_register_output);
void omapdss_unregister_output(struct omap_dss_device *out)
{
list_del(&out->list);
}
EXPORT_SYMBOL(omapdss_unregister_output);
bool omapdss_component_is_output(struct device_node *node)
{
struct omap_dss_device *out;
list_for_each_entry(out, &output_list, list) {
if (out->dev->of_node == node)
return true;
}
return false;
}
EXPORT_SYMBOL(omapdss_component_is_output);
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
{
struct omap_dss_device *out;
list_for_each_entry(out, &output_list, list) {
if (out->id == id)
return out;
}
return NULL;
}
EXPORT_SYMBOL(omap_dss_get_output);
struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
{
struct device_node *src_node;
struct omap_dss_device *out;
u32 reg;
src_node = dss_of_port_get_parent_device(port);
if (!src_node)
return NULL;
reg = dss_of_port_get_port_number(port);
list_for_each_entry(out, &output_list, list) {
if (out->dev->of_node == src_node && out->port_num == reg) {
of_node_put(src_node);
return omap_dss_get_device(out);
}
}
of_node_put(src_node);
return NULL;
}
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
{
while (dssdev->src)
dssdev = dssdev->src;
if (dssdev->id != 0)
return omap_dss_get_device(dssdev);
return NULL;
}
EXPORT_SYMBOL(omapdss_find_output_from_display);
static const struct dss_mgr_ops *dss_mgr_ops;
static struct omap_drm_private *dss_mgr_ops_priv;
int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops,
int dss_install_mgr_ops(struct dss_device *dss,
const struct dss_mgr_ops *mgr_ops,
struct omap_drm_private *priv)
{
if (dss_mgr_ops)
if (dss->mgr_ops)
return -EBUSY;
dss_mgr_ops = mgr_ops;
dss_mgr_ops_priv = priv;
dss->mgr_ops = mgr_ops;
dss->mgr_ops_priv = priv;
return 0;
}
EXPORT_SYMBOL(dss_install_mgr_ops);
void dss_uninstall_mgr_ops(void)
void dss_uninstall_mgr_ops(struct dss_device *dss)
{
dss_mgr_ops = NULL;
dss_mgr_ops_priv = NULL;
dss->mgr_ops = NULL;
dss->mgr_ops_priv = NULL;
}
EXPORT_SYMBOL(dss_uninstall_mgr_ops);
int dss_mgr_connect(struct omap_dss_device *dssdev, struct omap_dss_device *dst)
{
return dss_mgr_ops->connect(dss_mgr_ops_priv,
dssdev->dispc_channel, dst);
}
EXPORT_SYMBOL(dss_mgr_connect);
void dss_mgr_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
dss_mgr_ops->disconnect(dss_mgr_ops_priv, dssdev->dispc_channel, dst);
}
EXPORT_SYMBOL(dss_mgr_disconnect);
void dss_mgr_set_timings(struct omap_dss_device *dssdev,
const struct videomode *vm)
{
dss_mgr_ops->set_timings(dss_mgr_ops_priv, dssdev->dispc_channel, vm);
dssdev->dss->mgr_ops->set_timings(dssdev->dss->mgr_ops_priv,
dssdev->dispc_channel, vm);
}
EXPORT_SYMBOL(dss_mgr_set_timings);
void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev,
const struct dss_lcd_mgr_config *config)
{
dss_mgr_ops->set_lcd_config(dss_mgr_ops_priv,
dssdev->dispc_channel, config);
dssdev->dss->mgr_ops->set_lcd_config(dssdev->dss->mgr_ops_priv,
dssdev->dispc_channel, config);
}
EXPORT_SYMBOL(dss_mgr_set_lcd_config);
int dss_mgr_enable(struct omap_dss_device *dssdev)
{
return dss_mgr_ops->enable(dss_mgr_ops_priv, dssdev->dispc_channel);
return dssdev->dss->mgr_ops->enable(dssdev->dss->mgr_ops_priv,
dssdev->dispc_channel);
}
EXPORT_SYMBOL(dss_mgr_enable);
void dss_mgr_disable(struct omap_dss_device *dssdev)
{
dss_mgr_ops->disable(dss_mgr_ops_priv, dssdev->dispc_channel);
dssdev->dss->mgr_ops->disable(dssdev->dss->mgr_ops_priv,
dssdev->dispc_channel);
}
EXPORT_SYMBOL(dss_mgr_disable);
void dss_mgr_start_update(struct omap_dss_device *dssdev)
{
dss_mgr_ops->start_update(dss_mgr_ops_priv, dssdev->dispc_channel);
dssdev->dss->mgr_ops->start_update(dssdev->dss->mgr_ops_priv,
dssdev->dispc_channel);
}
EXPORT_SYMBOL(dss_mgr_start_update);
int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev,
void (*handler)(void *), void *data)
{
return dss_mgr_ops->register_framedone_handler(dss_mgr_ops_priv,
dssdev->dispc_channel,
handler, data);
struct dss_device *dss = dssdev->dss;
return dss->mgr_ops->register_framedone_handler(dss->mgr_ops_priv,
dssdev->dispc_channel,
handler, data);
}
EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev,
void (*handler)(void *), void *data)
{
dss_mgr_ops->unregister_framedone_handler(dss_mgr_ops_priv,
dssdev->dispc_channel,
handler, data);
struct dss_device *dss = dssdev->dss;
dss->mgr_ops->unregister_framedone_handler(dss->mgr_ops_priv,
dssdev->dispc_channel,
handler, data);
}
EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);

View file

@ -132,10 +132,8 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)
static int sdi_display_enable(struct omap_dss_device *dssdev)
{
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
struct videomode *vm = &sdi->vm;
unsigned long fck;
struct dispc_clock_info dispc_cinfo;
unsigned long pck;
unsigned long fck;
int r;
if (!sdi->output.dispc_channel_connected) {
@ -151,27 +149,12 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
/* 15.5.9.1.2 */
vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_SYNC_POSEDGE;
r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo);
r = sdi_calc_clock_div(sdi, sdi->vm.pixelclock, &fck, &dispc_cinfo);
if (r)
goto err_calc_clock_div;
sdi->mgr_config.clock_info = dispc_cinfo;
pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
if (pck != vm->pixelclock) {
DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
vm->pixelclock, pck);
vm->pixelclock = pck;
}
dss_mgr_set_timings(&sdi->output, vm);
r = dss_set_fck_rate(sdi->dss, fck);
if (r)
goto err_set_dss_clock_div;
@ -230,96 +213,63 @@ static void sdi_display_disable(struct omap_dss_device *dssdev)
}
static void sdi_set_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
const struct videomode *vm)
{
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
sdi->vm = *vm;
}
static void sdi_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
*vm = sdi->vm;
}
static int sdi_check_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
enum omap_channel channel = dssdev->dispc_channel;
if (!dispc_mgr_timings_ok(sdi->dss->dispc, channel, vm))
return -EINVAL;
struct dispc_clock_info dispc_cinfo;
unsigned long fck;
unsigned long pck;
int r;
if (vm->pixelclock == 0)
return -EINVAL;
return 0;
}
r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo);
if (r)
return r;
static int sdi_init_regulator(struct sdi_device *sdi)
{
struct regulator *vdds_sdi;
pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
if (sdi->vdds_sdi_reg)
return 0;
if (pck != vm->pixelclock) {
DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
vm->pixelclock, pck);
vdds_sdi = devm_regulator_get(&sdi->pdev->dev, "vdds_sdi");
if (IS_ERR(vdds_sdi)) {
if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
DSSERR("can't get VDDS_SDI regulator\n");
return PTR_ERR(vdds_sdi);
vm->pixelclock = pck;
}
sdi->vdds_sdi_reg = vdds_sdi;
return 0;
}
static int sdi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int sdi_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
int r;
r = sdi_init_regulator(sdi);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
r = dss_mgr_connect(&sdi->output, dssdev);
if (r)
return r;
r = omapdss_output_set_device(dssdev, dst);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dst->name);
dss_mgr_disconnect(&sdi->output, dssdev);
return r;
}
dst->dispc_channel_connected = true;
return 0;
}
static void sdi_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void sdi_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
dst->dispc_channel_connected = false;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
omapdss_output_unset_device(dssdev);
dss_mgr_disconnect(&sdi->output, dssdev);
omapdss_device_disconnect(dst, dst->next);
}
static const struct omapdss_sdi_ops sdi_ops = {
static const struct omap_dss_device_ops sdi_ops = {
.connect = sdi_connect,
.disconnect = sdi_disconnect,
@ -328,12 +278,12 @@ static const struct omapdss_sdi_ops sdi_ops = {
.check_timings = sdi_check_timings,
.set_timings = sdi_set_timings,
.get_timings = sdi_get_timings,
};
static void sdi_init_output(struct sdi_device *sdi)
static int sdi_init_output(struct sdi_device *sdi)
{
struct omap_dss_device *out = &sdi->output;
int r;
out->dev = &sdi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_SDI;
@ -341,16 +291,36 @@ static void sdi_init_output(struct sdi_device *sdi)
out->name = "sdi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
/* We have SDI only on OMAP3, where it's on port 1 */
out->port_num = 1;
out->ops.sdi = &sdi_ops;
out->of_ports = BIT(1);
out->ops = &sdi_ops;
out->owner = THIS_MODULE;
out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE /* 15.5.9.1.2 */
| DRM_BUS_FLAG_SYNC_POSEDGE;
omapdss_register_output(out);
out->next = omapdss_of_find_connected_device(out->dev->of_node, 1);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
}
r = omapdss_output_validate(out);
if (r) {
omapdss_device_put(out->next);
out->next = NULL;
return r;
}
omapdss_device_register(out);
return 0;
}
static void sdi_uninit_output(struct sdi_device *sdi)
{
omapdss_unregister_output(&sdi->output);
if (sdi->output.next)
omapdss_device_put(sdi->output.next);
omapdss_device_unregister(&sdi->output);
}
int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
@ -372,25 +342,32 @@ int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
}
r = of_property_read_u32(ep, "datapairs", &datapairs);
of_node_put(ep);
if (r) {
DSSERR("failed to parse datapairs\n");
goto err_datapairs;
goto err_free;
}
sdi->datapairs = datapairs;
sdi->dss = dss;
of_node_put(ep);
sdi->pdev = pdev;
port->data = sdi;
sdi_init_output(sdi);
sdi->vdds_sdi_reg = devm_regulator_get(&pdev->dev, "vdds_sdi");
if (IS_ERR(sdi->vdds_sdi_reg)) {
r = PTR_ERR(sdi->vdds_sdi_reg);
if (r != -EPROBE_DEFER)
DSSERR("can't get VDDS_SDI regulator\n");
goto err_free;
}
r = sdi_init_output(sdi);
if (r)
goto err_free;
return 0;
err_datapairs:
of_node_put(ep);
err_free:
kfree(sdi);

View file

@ -452,7 +452,7 @@ static void venc_runtime_put(struct venc_device *venc)
WARN_ON(r < 0 && r != -ENOSYS);
}
static const struct venc_config *venc_timings_to_config(struct videomode *vm)
static const struct venc_config *venc_timings_to_config(const struct videomode *vm)
{
switch (venc_get_videomode(vm)) {
default:
@ -491,8 +491,6 @@ static int venc_power_on(struct venc_device *venc)
venc_write_reg(venc, VENC_OUTPUT_CONTROL, l);
dss_mgr_set_timings(&venc->output, &venc->vm);
r = regulator_enable(venc->vdda_dac_reg);
if (r)
goto err1;
@ -568,32 +566,30 @@ static void venc_display_disable(struct omap_dss_device *dssdev)
mutex_unlock(&venc->venc_lock);
}
static void venc_set_timings(struct omap_dss_device *dssdev,
static void venc_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
struct videomode actual_vm;
mutex_lock(&venc->venc_lock);
*vm = venc->vm;
mutex_unlock(&venc->venc_lock);
}
static void venc_set_timings(struct omap_dss_device *dssdev,
const struct videomode *vm)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
DSSDBG("venc_set_timings\n");
mutex_lock(&venc->venc_lock);
switch (venc_get_videomode(vm)) {
default:
WARN_ON_ONCE(1);
case VENC_MODE_PAL:
actual_vm = omap_dss_pal_vm;
break;
case VENC_MODE_NTSC:
actual_vm = omap_dss_ntsc_vm;
break;
}
/* Reset WSS data when the TV standard changes. */
if (memcmp(&venc->vm, &actual_vm, sizeof(actual_vm)))
if (memcmp(&venc->vm, vm, sizeof(*vm)))
venc->wss_data = 0;
venc->vm = actual_vm;
venc->vm = *vm;
dispc_set_tv_pclk(venc->dss->dispc, 13500000);
@ -607,82 +603,18 @@ static int venc_check_timings(struct omap_dss_device *dssdev,
switch (venc_get_videomode(vm)) {
case VENC_MODE_PAL:
case VENC_MODE_NTSC:
*vm = omap_dss_pal_vm;
return 0;
case VENC_MODE_NTSC:
*vm = omap_dss_ntsc_vm;
return 0;
default:
return -EINVAL;
}
}
static void venc_get_timings(struct omap_dss_device *dssdev,
struct videomode *vm)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
mutex_lock(&venc->venc_lock);
*vm = venc->vm;
mutex_unlock(&venc->venc_lock);
}
static u32 venc_get_wss(struct omap_dss_device *dssdev)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
/* Invert due to VENC_L21_WC_CTL:INV=1 */
return (venc->wss_data >> 8) ^ 0xfffff;
}
static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
const struct venc_config *config;
int r;
DSSDBG("venc_set_wss\n");
mutex_lock(&venc->venc_lock);
config = venc_timings_to_config(&venc->vm);
/* Invert due to VENC_L21_WC_CTL:INV=1 */
venc->wss_data = (wss ^ 0xfffff) << 8;
r = venc_runtime_get(venc);
if (r)
goto err;
venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
venc->wss_data);
venc_runtime_put(venc);
err:
mutex_unlock(&venc->venc_lock);
return r;
}
static int venc_init_regulator(struct venc_device *venc)
{
struct regulator *vdda_dac;
if (venc->vdda_dac_reg != NULL)
return 0;
vdda_dac = devm_regulator_get(&venc->pdev->dev, "vdda");
if (IS_ERR(vdda_dac)) {
if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
DSSERR("can't get VDDA_DAC regulator\n");
return PTR_ERR(vdda_dac);
}
venc->vdda_dac_reg = vdda_dac;
return 0;
}
static int venc_dump_regs(struct seq_file *s, void *p)
{
struct venc_device *venc = s->private;
@ -760,47 +692,28 @@ static int venc_get_clocks(struct venc_device *venc)
return 0;
}
static int venc_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static int venc_connect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
int r;
r = venc_init_regulator(venc);
r = omapdss_device_connect(dst->dss, dst, dst->next);
if (r)
return r;
r = dss_mgr_connect(&venc->output, dssdev);
if (r)
return r;
r = omapdss_output_set_device(dssdev, dst);
if (r) {
DSSERR("failed to connect output to new device: %s\n",
dst->name);
dss_mgr_disconnect(&venc->output, dssdev);
return r;
}
dst->dispc_channel_connected = true;
return 0;
}
static void venc_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
static void venc_disconnect(struct omap_dss_device *src,
struct omap_dss_device *dst)
{
struct venc_device *venc = dssdev_to_venc(dssdev);
dst->dispc_channel_connected = false;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
omapdss_output_unset_device(dssdev);
dss_mgr_disconnect(&venc->output, dssdev);
omapdss_device_disconnect(dst, dst->next);
}
static const struct omapdss_atv_ops venc_ops = {
static const struct omap_dss_device_ops venc_ops = {
.connect = venc_connect,
.disconnect = venc_disconnect,
@ -808,31 +721,92 @@ static const struct omapdss_atv_ops venc_ops = {
.disable = venc_display_disable,
.check_timings = venc_check_timings,
.set_timings = venc_set_timings,
.get_timings = venc_get_timings,
.set_wss = venc_set_wss,
.get_wss = venc_get_wss,
.set_timings = venc_set_timings,
};
static void venc_init_output(struct venc_device *venc)
/* -----------------------------------------------------------------------------
* Component Bind & Unbind
*/
static int venc_bind(struct device *dev, struct device *master, void *data)
{
struct dss_device *dss = dss_get_device(master);
struct venc_device *venc = dev_get_drvdata(dev);
u8 rev_id;
int r;
venc->dss = dss;
r = venc_runtime_get(venc);
if (r)
return r;
rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);
dev_dbg(dev, "OMAP VENC rev %d\n", rev_id);
venc_runtime_put(venc);
venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,
venc);
return 0;
}
static void venc_unbind(struct device *dev, struct device *master, void *data)
{
struct venc_device *venc = dev_get_drvdata(dev);
dss_debugfs_remove_file(venc->debugfs);
}
static const struct component_ops venc_component_ops = {
.bind = venc_bind,
.unbind = venc_unbind,
};
/* -----------------------------------------------------------------------------
* Probe & Remove, Suspend & Resume
*/
static int venc_init_output(struct venc_device *venc)
{
struct omap_dss_device *out = &venc->output;
int r;
out->dev = &venc->pdev->dev;
out->id = OMAP_DSS_OUTPUT_VENC;
out->output_type = OMAP_DISPLAY_TYPE_VENC;
out->name = "venc.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
out->ops.atv = &venc_ops;
out->ops = &venc_ops;
out->owner = THIS_MODULE;
out->of_ports = BIT(0);
omapdss_register_output(out);
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
if (IS_ERR(out->next)) {
if (PTR_ERR(out->next) != -EPROBE_DEFER)
dev_err(out->dev, "failed to find video sink\n");
return PTR_ERR(out->next);
}
r = omapdss_output_validate(out);
if (r) {
omapdss_device_put(out->next);
out->next = NULL;
return r;
}
omapdss_device_register(out);
return 0;
}
static void venc_uninit_output(struct venc_device *venc)
{
omapdss_unregister_output(&venc->output);
if (venc->output.next)
omapdss_device_put(venc->output.next);
omapdss_device_unregister(&venc->output);
}
static int venc_probe_of(struct venc_device *venc)
@ -878,19 +852,15 @@ static int venc_probe_of(struct venc_device *venc)
return r;
}
/* VENC HW IP initialisation */
static const struct soc_device_attribute venc_soc_devices[] = {
{ .machine = "OMAP3[45]*" },
{ .machine = "AM35*" },
{ /* sentinel */ }
};
static int venc_bind(struct device *dev, struct device *master, void *data)
static int venc_probe(struct platform_device *pdev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dss_device *dss = dss_get_device(master);
struct venc_device *venc;
u8 rev_id;
struct resource *venc_mem;
int r;
@ -899,8 +869,8 @@ static int venc_bind(struct device *dev, struct device *master, void *data)
return -ENOMEM;
venc->pdev = pdev;
venc->dss = dss;
dev_set_drvdata(dev, venc);
platform_set_drvdata(pdev, venc);
/* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */
if (soc_device_match(venc_soc_devices))
@ -909,6 +879,7 @@ static int venc_bind(struct device *dev, struct device *master, void *data)
mutex_init(&venc->venc_lock);
venc->wss_data = 0;
venc->vm = omap_dss_pal_vm;
venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0);
venc->base = devm_ioremap_resource(&pdev->dev, venc_mem);
@ -917,68 +888,54 @@ static int venc_bind(struct device *dev, struct device *master, void *data)
goto err_free;
}
venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda");
if (IS_ERR(venc->vdda_dac_reg)) {
r = PTR_ERR(venc->vdda_dac_reg);
if (r != -EPROBE_DEFER)
DSSERR("can't get VDDA_DAC regulator\n");
goto err_free;
}
r = venc_get_clocks(venc);
if (r)
goto err_free;
r = venc_probe_of(venc);
if (r)
goto err_free;
pm_runtime_enable(&pdev->dev);
r = venc_runtime_get(venc);
r = venc_init_output(venc);
if (r)
goto err_runtime_get;
goto err_pm_disable;
rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);
dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
venc_runtime_put(venc);
r = venc_probe_of(venc);
if (r) {
DSSERR("Invalid DT data\n");
goto err_probe_of;
}
venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,
venc);
venc_init_output(venc);
r = component_add(&pdev->dev, &venc_component_ops);
if (r)
goto err_uninit_output;
return 0;
err_probe_of:
err_runtime_get:
err_uninit_output:
venc_uninit_output(venc);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
err_free:
kfree(venc);
return r;
}
static void venc_unbind(struct device *dev, struct device *master, void *data)
static int venc_remove(struct platform_device *pdev)
{
struct venc_device *venc = dev_get_drvdata(dev);
struct venc_device *venc = platform_get_drvdata(pdev);
dss_debugfs_remove_file(venc->debugfs);
component_del(&pdev->dev, &venc_component_ops);
venc_uninit_output(venc);
pm_runtime_disable(dev);
pm_runtime_disable(&pdev->dev);
kfree(venc);
}
static const struct component_ops venc_component_ops = {
.bind = venc_bind,
.unbind = venc_unbind,
};
static int venc_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &venc_component_ops);
}
static int venc_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &venc_component_ops);
return 0;
}

View file

@ -29,10 +29,28 @@
struct omap_connector {
struct drm_connector base;
struct omap_dss_device *dssdev;
struct omap_dss_device *output;
struct omap_dss_device *display;
struct omap_dss_device *hpd;
bool hdmi_mode;
};
static void omap_connector_hpd_notify(struct drm_connector *connector,
struct omap_dss_device *src,
enum drm_connector_status status)
{
if (status == connector_status_disconnected) {
/*
* If the source is an HDMI encoder, notify it of disconnection.
* This is required to let the HDMI encoder reset any internal
* state related to connection status, such as the CEC address.
*/
if (src && src->type == OMAP_DISPLAY_TYPE_HDMI &&
src->ops->hdmi.lost_hotplug)
src->ops->hdmi.lost_hotplug(src);
}
}
static void omap_connector_hpd_cb(void *cb_data,
enum drm_connector_status status)
{
@ -46,8 +64,31 @@ static void omap_connector_hpd_cb(void *cb_data,
connector->status = status;
mutex_unlock(&dev->mode_config.mutex);
if (old_status != status)
drm_kms_helper_hotplug_event(dev);
if (old_status == status)
return;
omap_connector_hpd_notify(connector, omap_connector->hpd, status);
drm_kms_helper_hotplug_event(dev);
}
void omap_connector_enable_hpd(struct drm_connector *connector)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *hpd = omap_connector->hpd;
if (hpd)
hpd->ops->register_hpd_cb(hpd, omap_connector_hpd_cb,
omap_connector);
}
void omap_connector_disable_hpd(struct drm_connector *connector)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *hpd = omap_connector->hpd;
if (hpd)
hpd->ops->unregister_hpd_cb(hpd);
}
bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
@ -57,120 +98,179 @@ bool omap_connector_get_hdmi_mode(struct drm_connector *connector)
return omap_connector->hdmi_mode;
}
static struct omap_dss_device *
omap_connector_find_device(struct drm_connector *connector,
enum omap_dss_device_ops_flag op)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev;
for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
if (dssdev->ops_flags & op)
return dssdev;
}
return NULL;
}
static enum drm_connector_status omap_connector_detect(
struct drm_connector *connector, bool force)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev = omap_connector->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
enum drm_connector_status ret;
struct omap_dss_device *dssdev;
enum drm_connector_status status;
if (dssdrv->detect) {
if (dssdrv->detect(dssdev))
ret = connector_status_connected;
else
ret = connector_status_disconnected;
} else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI ||
dssdev->type == OMAP_DISPLAY_TYPE_DBI ||
dssdev->type == OMAP_DISPLAY_TYPE_SDI ||
dssdev->type == OMAP_DISPLAY_TYPE_DSI) {
ret = connector_status_connected;
dssdev = omap_connector_find_device(connector,
OMAP_DSS_DEVICE_OP_DETECT);
if (dssdev) {
status = dssdev->ops->detect(dssdev)
? connector_status_connected
: connector_status_disconnected;
omap_connector_hpd_notify(connector, dssdev->src, status);
} else {
ret = connector_status_unknown;
switch (omap_connector->display->type) {
case OMAP_DISPLAY_TYPE_DPI:
case OMAP_DISPLAY_TYPE_DBI:
case OMAP_DISPLAY_TYPE_SDI:
case OMAP_DISPLAY_TYPE_DSI:
status = connector_status_connected;
break;
default:
status = connector_status_unknown;
break;
}
}
VERB("%s: %d (force=%d)", omap_connector->dssdev->name, ret, force);
VERB("%s: %d (force=%d)", omap_connector->display->name, status, force);
return ret;
return status;
}
static void omap_connector_destroy(struct drm_connector *connector)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev = omap_connector->dssdev;
DBG("%s", omap_connector->dssdev->name);
if (connector->polled == DRM_CONNECTOR_POLL_HPD &&
dssdev->driver->unregister_hpd_cb) {
dssdev->driver->unregister_hpd_cb(dssdev);
DBG("%s", omap_connector->display->name);
if (omap_connector->hpd) {
struct omap_dss_device *hpd = omap_connector->hpd;
hpd->ops->unregister_hpd_cb(hpd);
omapdss_device_put(hpd);
omap_connector->hpd = NULL;
}
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
kfree(omap_connector);
omap_dss_put_device(dssdev);
omapdss_device_put(omap_connector->output);
omapdss_device_put(omap_connector->display);
}
#define MAX_EDID 512
static int omap_connector_get_modes_edid(struct drm_connector *connector,
struct omap_dss_device *dssdev)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
enum drm_connector_status status;
void *edid;
int n;
status = omap_connector_detect(connector, false);
if (status != connector_status_connected)
goto no_edid;
edid = kzalloc(MAX_EDID, GFP_KERNEL);
if (!edid)
goto no_edid;
if (dssdev->ops->read_edid(dssdev, edid, MAX_EDID) <= 0 ||
!drm_edid_is_valid(edid)) {
kfree(edid);
goto no_edid;
}
drm_connector_update_edid_property(connector, edid);
n = drm_add_edid_modes(connector, edid);
omap_connector->hdmi_mode = drm_detect_hdmi_monitor(edid);
kfree(edid);
return n;
no_edid:
drm_connector_update_edid_property(connector, NULL);
return 0;
}
static int omap_connector_get_modes(struct drm_connector *connector)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev = omap_connector->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
struct drm_device *dev = connector->dev;
int n = 0;
struct omap_dss_device *dssdev;
struct drm_display_mode *mode;
struct videomode vm = {0};
DBG("%s", omap_connector->dssdev->name);
DBG("%s", omap_connector->display->name);
/* if display exposes EDID, then we parse that in the normal way to
* build table of supported modes.. otherwise (ie. fixed resolution
* LCD panels) we just return a single mode corresponding to the
* currently configured timings:
/*
* If display exposes EDID, then we parse that in the normal way to
* build table of supported modes.
*/
if (dssdrv->read_edid) {
void *edid = kzalloc(MAX_EDID, GFP_KERNEL);
dssdev = omap_connector_find_device(connector,
OMAP_DSS_DEVICE_OP_EDID);
if (dssdev)
return omap_connector_get_modes_edid(connector, dssdev);
if (!edid)
return 0;
if ((dssdrv->read_edid(dssdev, edid, MAX_EDID) > 0) &&
drm_edid_is_valid(edid)) {
drm_connector_update_edid_property(
connector, edid);
n = drm_add_edid_modes(connector, edid);
omap_connector->hdmi_mode =
drm_detect_hdmi_monitor(edid);
} else {
drm_connector_update_edid_property(
connector, NULL);
}
kfree(edid);
} else {
struct drm_display_mode *mode = drm_mode_create(dev);
struct videomode vm = {0};
if (!mode)
return 0;
dssdrv->get_timings(dssdev, &vm);
drm_display_mode_from_videomode(&vm, mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
if (dssdrv->get_size) {
dssdrv->get_size(dssdev,
/*
* Otherwise we have either a fixed resolution panel or an output that
* doesn't support modes discovery (e.g. DVI or VGA with the DDC bus
* unconnected, or analog TV). Start by querying the size.
*/
dssdev = omap_connector->display;
if (dssdev->driver && dssdev->driver->get_size)
dssdev->driver->get_size(dssdev,
&connector->display_info.width_mm,
&connector->display_info.height_mm);
}
n = 1;
/*
* Iterate over the pipeline to find the first device that can provide
* timing information. If we can't find any, we just let the KMS core
* add the default modes.
*/
for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
if (dssdev->ops->get_timings)
break;
}
if (!dssdev)
return 0;
return n;
/* Add a single mode corresponding to the fixed panel timings. */
mode = drm_mode_create(connector->dev);
if (!mode)
return 0;
dssdev->ops->get_timings(dssdev, &vm);
drm_display_mode_from_videomode(&vm, mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_set_name(mode);
drm_mode_probed_add(connector, mode);
return 1;
}
static int omap_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev = omap_connector->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
enum omap_channel channel = omap_connector->output->dispc_channel;
struct omap_drm_private *priv = connector->dev->dev_private;
struct omap_dss_device *dssdev;
struct videomode vm = {0};
struct drm_device *dev = connector->dev;
struct drm_display_mode *new_mode;
@ -179,44 +279,31 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
drm_display_mode_to_videomode(mode, &vm);
mode->vrefresh = drm_mode_vrefresh(mode);
/*
* if the panel driver doesn't have a check_timings, it's most likely
* a fixed resolution panel, check if the timings match with the
* panel's timings
*/
if (dssdrv->check_timings) {
r = dssdrv->check_timings(dssdev, &vm);
} else {
struct videomode t = {0};
r = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
if (r)
goto done;
dssdrv->get_timings(dssdev, &t);
for (dssdev = omap_connector->output; dssdev; dssdev = dssdev->next) {
if (!dssdev->ops->check_timings)
continue;
/*
* Ignore the flags, as we don't get them from
* drm_display_mode_to_videomode.
*/
t.flags = 0;
if (memcmp(&vm, &t, sizeof(vm)))
r = -EINVAL;
else
r = 0;
r = dssdev->ops->check_timings(dssdev, &vm);
if (r)
goto done;
}
if (!r) {
/* check if vrefresh is still valid */
new_mode = drm_mode_duplicate(dev, mode);
/* check if vrefresh is still valid */
new_mode = drm_mode_duplicate(dev, mode);
if (!new_mode)
return MODE_BAD;
if (!new_mode)
return MODE_BAD;
new_mode->clock = vm.pixelclock / 1000;
new_mode->vrefresh = 0;
if (mode->vrefresh == drm_mode_vrefresh(new_mode))
ret = MODE_OK;
drm_mode_destroy(dev, new_mode);
}
new_mode->clock = vm.pixelclock / 1000;
new_mode->vrefresh = 0;
if (mode->vrefresh == drm_mode_vrefresh(new_mode))
ret = MODE_OK;
drm_mode_destroy(dev, new_mode);
done:
DBG("connector: mode %s: "
"%d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
(ret == MODE_OK) ? "valid" : "invalid",
@ -243,53 +330,73 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
.mode_valid = omap_connector_mode_valid,
};
static int omap_connector_get_type(struct omap_dss_device *display)
{
switch (display->type) {
case OMAP_DISPLAY_TYPE_HDMI:
return DRM_MODE_CONNECTOR_HDMIA;
case OMAP_DISPLAY_TYPE_DVI:
return DRM_MODE_CONNECTOR_DVID;
case OMAP_DISPLAY_TYPE_DSI:
return DRM_MODE_CONNECTOR_DSI;
case OMAP_DISPLAY_TYPE_DPI:
case OMAP_DISPLAY_TYPE_DBI:
return DRM_MODE_CONNECTOR_DPI;
case OMAP_DISPLAY_TYPE_VENC:
/* TODO: This could also be composite */
return DRM_MODE_CONNECTOR_SVIDEO;
case OMAP_DISPLAY_TYPE_SDI:
return DRM_MODE_CONNECTOR_LVDS;
default:
return DRM_MODE_CONNECTOR_Unknown;
}
}
/* initialize connector */
struct drm_connector *omap_connector_init(struct drm_device *dev,
int connector_type, struct omap_dss_device *dssdev,
struct drm_encoder *encoder)
struct omap_dss_device *output,
struct omap_dss_device *display,
struct drm_encoder *encoder)
{
struct drm_connector *connector = NULL;
struct omap_connector *omap_connector;
bool hpd_supported = false;
struct omap_dss_device *dssdev;
DBG("%s", dssdev->name);
omap_dss_get_device(dssdev);
DBG("%s", display->name);
omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
if (!omap_connector)
goto fail;
omap_connector->dssdev = dssdev;
omap_connector->output = omapdss_device_get(output);
omap_connector->display = omapdss_device_get(display);
connector = &omap_connector->base;
drm_connector_init(dev, connector, &omap_connector_funcs,
connector_type);
drm_connector_helper_add(connector, &omap_connector_helper_funcs);
if (dssdev->driver->register_hpd_cb) {
int ret = dssdev->driver->register_hpd_cb(dssdev,
omap_connector_hpd_cb,
omap_connector);
if (!ret)
hpd_supported = true;
else if (ret != -ENOTSUPP)
DBG("%s: Failed to register HPD callback (%d).",
dssdev->name, ret);
}
if (hpd_supported)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else if (dssdev->driver->detect)
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
else
connector->polled = 0;
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
drm_connector_init(dev, connector, &omap_connector_funcs,
omap_connector_get_type(display));
drm_connector_helper_add(connector, &omap_connector_helper_funcs);
/*
* Initialize connector status handling. First try to find a device that
* supports hot-plug reporting. If it fails, fall back to a device that
* support polling. If that fails too, we don't support hot-plug
* detection at all.
*/
dssdev = omap_connector_find_device(connector, OMAP_DSS_DEVICE_OP_HPD);
if (dssdev) {
omap_connector->hpd = omapdss_device_get(dssdev);
connector->polled = DRM_CONNECTOR_POLL_HPD;
} else {
dssdev = omap_connector_find_device(connector,
OMAP_DSS_DEVICE_OP_DETECT);
if (dssdev)
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
}
return connector;
fail:

View file

@ -28,10 +28,13 @@ struct drm_encoder;
struct omap_dss_device;
struct drm_connector *omap_connector_init(struct drm_device *dev,
int connector_type, struct omap_dss_device *dssdev,
struct drm_encoder *encoder);
struct omap_dss_device *output,
struct omap_dss_device *display,
struct drm_encoder *encoder);
struct drm_encoder *omap_connector_attached_encoder(
struct drm_connector *connector);
bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
void omap_connector_enable_hpd(struct drm_connector *connector);
void omap_connector_disable_hpd(struct drm_connector *connector);
#endif /* __OMAPDRM_CONNECTOR_H__ */

View file

@ -41,6 +41,7 @@ struct omap_crtc {
struct drm_crtc base;
const char *name;
struct omap_drm_pipeline *pipe;
enum omap_channel channel;
struct videomode vm;
@ -108,38 +109,7 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
* job of sequencing the setup of the video pipe in the proper order
*/
/* 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_drm_private *priv,
enum omap_channel channel,
struct omap_dss_device *dst)
{
const struct dispc_ops *dispc_ops = priv->dispc_ops;
struct dispc_device *dispc = priv->dispc;
if (omap_crtc_output[channel])
return -EINVAL;
if (!(dispc_ops->mgr_get_supported_outputs(dispc, channel) & dst->id))
return -EINVAL;
omap_crtc_output[channel] = dst;
dst->dispc_channel_connected = true;
return 0;
}
static void omap_crtc_dss_disconnect(struct omap_drm_private *priv,
enum omap_channel channel,
struct omap_dss_device *dst)
{
omap_crtc_output[channel] = NULL;
dst->dispc_channel_connected = false;
}
static void omap_crtc_dss_start_update(struct omap_drm_private *priv,
enum omap_channel channel)
{
@ -159,7 +129,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
if (WARN_ON(omap_crtc->enabled == enable))
return;
if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) {
if (omap_crtc->pipe->output->output_type == OMAP_DISPLAY_TYPE_HDMI) {
priv->dispc_ops->mgr_enable(priv->dispc, channel, enable);
omap_crtc->enabled = enable;
return;
@ -215,7 +185,8 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
static int omap_crtc_dss_enable(struct omap_drm_private *priv,
enum omap_channel channel)
{
struct omap_crtc *omap_crtc = omap_crtcs[channel];
struct drm_crtc *crtc = priv->channels[channel]->crtc;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
priv->dispc_ops->mgr_set_timings(priv->dispc, omap_crtc->channel,
&omap_crtc->vm);
@ -227,7 +198,8 @@ static int omap_crtc_dss_enable(struct omap_drm_private *priv,
static void omap_crtc_dss_disable(struct omap_drm_private *priv,
enum omap_channel channel)
{
struct omap_crtc *omap_crtc = omap_crtcs[channel];
struct drm_crtc *crtc = priv->channels[channel]->crtc;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
omap_crtc_set_enabled(&omap_crtc->base, false);
}
@ -236,7 +208,9 @@ static void omap_crtc_dss_set_timings(struct omap_drm_private *priv,
enum omap_channel channel,
const struct videomode *vm)
{
struct omap_crtc *omap_crtc = omap_crtcs[channel];
struct drm_crtc *crtc = priv->channels[channel]->crtc;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->name);
omap_crtc->vm = *vm;
}
@ -245,7 +219,8 @@ static void omap_crtc_dss_set_lcd_config(struct omap_drm_private *priv,
enum omap_channel channel,
const struct dss_lcd_mgr_config *config)
{
struct omap_crtc *omap_crtc = omap_crtcs[channel];
struct drm_crtc *crtc = priv->channels[channel]->crtc;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
DBG("%s", omap_crtc->name);
priv->dispc_ops->mgr_set_lcd_config(priv->dispc, omap_crtc->channel,
@ -266,8 +241,6 @@ static void omap_crtc_dss_unregister_framedone(
}
static const struct dss_mgr_ops mgr_ops = {
.connect = omap_crtc_dss_connect,
.disconnect = omap_crtc_dss_disconnect,
.start_update = omap_crtc_dss_start_update,
.enable = omap_crtc_dss_enable,
.disable = omap_crtc_dss_disable,
@ -447,11 +420,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
struct omap_drm_private *priv = crtc->dev->dev_private;
const u32 flags_mask = DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_DE_LOW |
DISPLAY_FLAGS_PIXDATA_POSEDGE | DISPLAY_FLAGS_PIXDATA_NEGEDGE |
DISPLAY_FLAGS_SYNC_POSEDGE | DISPLAY_FLAGS_SYNC_NEGEDGE;
unsigned int i;
DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
omap_crtc->name, mode->base.id, mode->name,
@ -461,38 +429,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
mode->type, mode->flags);
drm_display_mode_to_videomode(mode, &omap_crtc->vm);
/*
* HACK: This fixes the vm flags.
* struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags
* and they get lost when converting back and forth between
* struct drm_display_mode and struct videomode. The hack below
* goes and fetches the missing flags from the panel drivers.
*
* Correct solution would be to use DRM's bus-flags, but that's not
* easily possible before the omapdrm's panel/encoder driver model
* has been changed to the DRM model.
*/
for (i = 0; i < priv->num_encoders; ++i) {
struct drm_encoder *encoder = priv->encoders[i];
if (encoder->crtc == crtc) {
struct omap_dss_device *dssdev;
dssdev = omap_encoder_get_dssdev(encoder);
if (dssdev) {
struct videomode vm = {0};
dssdev->driver->get_timings(dssdev, &vm);
omap_crtc->vm.flags |= vm.flags & flags_mask;
}
break;
}
}
}
static int omap_crtc_atomic_check(struct drm_crtc *crtc,
@ -681,37 +617,29 @@ static const char *channel_names[] = {
void omap_crtc_pre_init(struct omap_drm_private *priv)
{
memset(omap_crtcs, 0, sizeof(omap_crtcs));
dss_install_mgr_ops(&mgr_ops, priv);
dss_install_mgr_ops(priv->dss, &mgr_ops, priv);
}
void omap_crtc_pre_uninit(void)
void omap_crtc_pre_uninit(struct omap_drm_private *priv)
{
dss_uninstall_mgr_ops();
dss_uninstall_mgr_ops(priv->dss);
}
/* initialize crtc */
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, struct omap_dss_device *dssdev)
struct omap_drm_pipeline *pipe,
struct drm_plane *plane)
{
struct omap_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc = NULL;
struct omap_crtc *omap_crtc;
enum omap_channel channel;
struct omap_dss_device *out;
int ret;
out = omapdss_find_output_from_display(dssdev);
channel = out->dispc_channel;
omap_dss_put_device(out);
channel = pipe->output->dispc_channel;
DBG("%s", channel_names[channel]);
/* Multiple displays on same channel is not allowed */
if (WARN_ON(omap_crtcs[channel] != NULL))
return ERR_PTR(-EINVAL);
omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
if (!omap_crtc)
return ERR_PTR(-ENOMEM);
@ -720,6 +648,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
init_waitqueue_head(&omap_crtc->pending_wait);
omap_crtc->pipe = pipe;
omap_crtc->channel = channel;
omap_crtc->name = channel_names[channel];
@ -727,7 +656,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
&omap_crtc_funcs, NULL);
if (ret < 0) {
dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
__func__, dssdev->name);
__func__, pipe->display->name);
kfree(omap_crtc);
return ERR_PTR(ret);
}
@ -750,7 +679,5 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_plane_install_properties(crtc->primary, &crtc->base);
omap_crtcs[channel] = omap_crtc;
return crtc;
}

View file

@ -27,15 +27,17 @@ enum omap_channel;
struct drm_crtc;
struct drm_device;
struct drm_plane;
struct omap_drm_pipeline;
struct omap_dss_device;
struct videomode;
struct videomode *omap_crtc_timings(struct drm_crtc *crtc);
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
void omap_crtc_pre_init(struct omap_drm_private *priv);
void omap_crtc_pre_uninit(void);
void omap_crtc_pre_uninit(struct omap_drm_private *priv);
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, struct omap_dss_device *dssdev);
struct omap_drm_pipeline *pipe,
struct drm_plane *plane);
int omap_crtc_wait_pending(struct drm_crtc *crtc);
void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus);
void omap_crtc_vblank_irq(struct drm_crtc *crtc);

View file

@ -15,6 +15,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/of.h>
#include <linux/sort.h>
#include <linux/sys_soc.h>
#include <drm/drm_atomic.h>
@ -127,55 +129,92 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
static int get_connector_type(struct omap_dss_device *dssdev)
static void omap_disconnect_pipelines(struct drm_device *ddev)
{
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_HDMI:
return DRM_MODE_CONNECTOR_HDMIA;
case OMAP_DISPLAY_TYPE_DVI:
return DRM_MODE_CONNECTOR_DVID;
case OMAP_DISPLAY_TYPE_DSI:
return DRM_MODE_CONNECTOR_DSI;
case OMAP_DISPLAY_TYPE_DPI:
case OMAP_DISPLAY_TYPE_DBI:
return DRM_MODE_CONNECTOR_DPI;
case OMAP_DISPLAY_TYPE_VENC:
/* TODO: This could also be composite */
return DRM_MODE_CONNECTOR_SVIDEO;
case OMAP_DISPLAY_TYPE_SDI:
return DRM_MODE_CONNECTOR_LVDS;
default:
return DRM_MODE_CONNECTOR_Unknown;
struct omap_drm_private *priv = ddev->dev_private;
unsigned int i;
for (i = 0; i < priv->num_pipes; i++) {
struct omap_drm_pipeline *pipe = &priv->pipes[i];
omapdss_device_disconnect(NULL, pipe->output);
omapdss_device_put(pipe->output);
omapdss_device_put(pipe->display);
pipe->output = NULL;
pipe->display = NULL;
}
memset(&priv->channels, 0, sizeof(priv->channels));
priv->num_pipes = 0;
}
static void omap_disconnect_dssdevs(void)
static int omap_compare_pipes(const void *a, const void *b)
{
struct omap_dss_device *dssdev = NULL;
const struct omap_drm_pipeline *pipe1 = a;
const struct omap_drm_pipeline *pipe2 = b;
for_each_dss_dev(dssdev)
dssdev->driver->disconnect(dssdev);
if (pipe1->display->alias_id > pipe2->display->alias_id)
return 1;
else if (pipe1->display->alias_id < pipe2->display->alias_id)
return -1;
return 0;
}
static int omap_connect_dssdevs(void)
static int omap_connect_pipelines(struct drm_device *ddev)
{
struct omap_drm_private *priv = ddev->dev_private;
struct omap_dss_device *output = NULL;
unsigned int i;
int r;
struct omap_dss_device *dssdev = NULL;
if (!omapdss_stack_is_ready())
return -EPROBE_DEFER;
for_each_dss_dev(dssdev) {
r = dssdev->driver->connect(dssdev);
for_each_dss_output(output) {
r = omapdss_device_connect(priv->dss, NULL, output);
if (r == -EPROBE_DEFER) {
omap_dss_put_device(dssdev);
omapdss_device_put(output);
goto cleanup;
} else if (r) {
dev_warn(dssdev->dev, "could not connect display: %s\n",
dssdev->name);
dev_warn(output->dev, "could not connect output %s\n",
output->name);
} else {
struct omap_drm_pipeline *pipe;
pipe = &priv->pipes[priv->num_pipes++];
pipe->output = omapdss_device_get(output);
pipe->display = omapdss_display_get(output);
if (priv->num_pipes == ARRAY_SIZE(priv->pipes)) {
/* To balance the 'for_each_dss_output' loop */
omapdss_device_put(output);
break;
}
}
}
/* Sort the list by DT aliases */
sort(priv->pipes, priv->num_pipes, sizeof(priv->pipes[0]),
omap_compare_pipes, NULL);
/*
* Populate the pipeline lookup table by DISPC channel. Only one display
* is allowed per channel.
*/
for (i = 0; i < priv->num_pipes; ++i) {
struct omap_drm_pipeline *pipe = &priv->pipes[i];
enum omap_channel channel = pipe->output->dispc_channel;
if (WARN_ON(priv->channels[channel] != NULL)) {
r = -EINVAL;
goto cleanup;
}
priv->channels[channel] = pipe;
}
return 0;
cleanup:
@ -183,7 +222,7 @@ static int omap_connect_dssdevs(void)
* if we are deferring probe, we disconnect the devices we previously
* connected
*/
omap_disconnect_dssdevs();
omap_disconnect_pipelines(ddev);
return r;
}
@ -204,10 +243,9 @@ static int omap_modeset_init_properties(struct drm_device *dev)
static int omap_modeset_init(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
struct omap_dss_device *dssdev = NULL;
int num_ovls = priv->dispc_ops->get_num_ovls(priv->dispc);
int num_mgrs = priv->dispc_ops->get_num_mgrs(priv->dispc);
int num_crtcs, crtc_idx, plane_idx;
unsigned int i;
int ret;
u32 plane_crtc_mask;
@ -225,87 +263,62 @@ static int omap_modeset_init(struct drm_device *dev)
* configuration does not match the expectations or exceeds
* the available resources, the configuration is rejected.
*/
num_crtcs = 0;
for_each_dss_dev(dssdev)
if (omapdss_device_is_connected(dssdev))
num_crtcs++;
if (num_crtcs > num_mgrs || num_crtcs > num_ovls ||
num_crtcs > ARRAY_SIZE(priv->crtcs) ||
num_crtcs > ARRAY_SIZE(priv->planes) ||
num_crtcs > ARRAY_SIZE(priv->encoders) ||
num_crtcs > ARRAY_SIZE(priv->connectors)) {
if (priv->num_pipes > num_mgrs || priv->num_pipes > num_ovls) {
dev_err(dev->dev, "%s(): Too many connected displays\n",
__func__);
return -EINVAL;
}
/* All planes can be put to any CRTC */
plane_crtc_mask = (1 << num_crtcs) - 1;
/* Create all planes first. They can all be put to any CRTC. */
plane_crtc_mask = (1 << priv->num_pipes) - 1;
dssdev = NULL;
crtc_idx = 0;
plane_idx = 0;
for_each_dss_dev(dssdev) {
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_plane *plane;
struct drm_crtc *crtc;
if (!omapdss_device_is_connected(dssdev))
continue;
encoder = omap_encoder_init(dev, dssdev);
if (!encoder)
return -ENOMEM;
connector = omap_connector_init(dev,
get_connector_type(dssdev), dssdev, encoder);
if (!connector)
return -ENOMEM;
plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY,
plane_crtc_mask);
if (IS_ERR(plane))
return PTR_ERR(plane);
crtc = omap_crtc_init(dev, plane, dssdev);
if (IS_ERR(crtc))
return PTR_ERR(crtc);
drm_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << crtc_idx);
priv->crtcs[priv->num_crtcs++] = crtc;
priv->planes[priv->num_planes++] = plane;
priv->encoders[priv->num_encoders++] = encoder;
priv->connectors[priv->num_connectors++] = connector;
plane_idx++;
crtc_idx++;
}
/*
* Create normal planes for the remaining overlays:
*/
for (; plane_idx < num_ovls; plane_idx++) {
for (i = 0; i < num_ovls; i++) {
enum drm_plane_type type = i < priv->num_pipes
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY;
struct drm_plane *plane;
if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)))
return -EINVAL;
plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY,
plane_crtc_mask);
plane = omap_plane_init(dev, i, type, plane_crtc_mask);
if (IS_ERR(plane))
return PTR_ERR(plane);
priv->planes[priv->num_planes++] = plane;
}
DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
priv->num_planes, priv->num_crtcs, priv->num_encoders,
priv->num_connectors);
/* Create the CRTCs, encoders and connectors. */
for (i = 0; i < priv->num_pipes; i++) {
struct omap_drm_pipeline *pipe = &priv->pipes[i];
struct omap_dss_device *display = pipe->display;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
encoder = omap_encoder_init(dev, pipe->output, display);
if (!encoder)
return -ENOMEM;
connector = omap_connector_init(dev, pipe->output, display,
encoder);
if (!connector)
return -ENOMEM;
crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
if (IS_ERR(crtc))
return PTR_ERR(crtc);
drm_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = 1 << i;
pipe->crtc = crtc;
pipe->encoder = encoder;
pipe->connector = connector;
}
DBG("registered %u planes, %u crtcs/encoders/connectors\n",
priv->num_planes, priv->num_pipes);
dev->mode_config.min_width = 8;
dev->mode_config.min_height = 2;
@ -335,27 +348,25 @@ static int omap_modeset_init(struct drm_device *dev)
/*
* Enable the HPD in external components if supported
*/
static void omap_modeset_enable_external_hpd(void)
static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
{
struct omap_dss_device *dssdev = NULL;
struct omap_drm_private *priv = ddev->dev_private;
int i;
for_each_dss_dev(dssdev) {
if (dssdev->driver->enable_hpd)
dssdev->driver->enable_hpd(dssdev);
}
for (i = 0; i < priv->num_pipes; i++)
omap_connector_enable_hpd(priv->pipes[i].connector);
}
/*
* Disable the HPD in external components if supported
*/
static void omap_modeset_disable_external_hpd(void)
static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
{
struct omap_dss_device *dssdev = NULL;
struct omap_drm_private *priv = ddev->dev_private;
int i;
for_each_dss_dev(dssdev) {
if (dssdev->driver->disable_hpd)
dssdev->driver->disable_hpd(dssdev);
}
for (i = 0; i < priv->num_pipes; i++)
omap_connector_disable_hpd(priv->pipes[i].connector);
}
/*
@ -525,6 +536,14 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
DBG("%s", dev_name(dev));
/* Allocate and initialize the DRM device. */
ddev = drm_dev_alloc(&omap_drm_driver, dev);
if (IS_ERR(ddev))
return PTR_ERR(ddev);
priv->ddev = ddev;
ddev->dev_private = priv;
priv->dev = dev;
priv->dss = omapdss_get_dss();
priv->dispc = dispc_get_dispc(priv->dss);
@ -532,7 +551,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
omap_crtc_pre_init(priv);
ret = omap_connect_dssdevs();
ret = omap_connect_pipelines(ddev);
if (ret)
goto err_crtc_uninit;
@ -543,16 +562,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
mutex_init(&priv->list_lock);
INIT_LIST_HEAD(&priv->obj_list);
/* Allocate and initialize the DRM device. */
ddev = drm_dev_alloc(&omap_drm_driver, priv->dev);
if (IS_ERR(ddev)) {
ret = PTR_ERR(ddev);
goto err_destroy_wq;
}
priv->ddev = ddev;
ddev->dev_private = priv;
/* Get memory bandwidth limits */
if (priv->dispc_ops->get_memory_bandwidth_limit)
priv->max_bandwidth =
@ -563,23 +572,23 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
ret = omap_modeset_init(ddev);
if (ret) {
dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
goto err_free_drm_dev;
goto err_gem_deinit;
}
/* Initialize vblank handling, start with all CRTCs disabled. */
ret = drm_vblank_init(ddev, priv->num_crtcs);
ret = drm_vblank_init(ddev, priv->num_pipes);
if (ret) {
dev_err(priv->dev, "could not init vblank\n");
goto err_cleanup_modeset;
}
for (i = 0; i < priv->num_crtcs; i++)
drm_crtc_vblank_off(priv->crtcs[i]);
for (i = 0; i < priv->num_pipes; i++)
drm_crtc_vblank_off(priv->pipes[i].crtc);
omap_fbdev_init(ddev);
drm_kms_helper_poll_init(ddev);
omap_modeset_enable_external_hpd();
omap_modeset_enable_external_hpd(ddev);
/*
* Register the DRM device with the core and the connectors with
@ -592,21 +601,20 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
return 0;
err_cleanup_helpers:
omap_modeset_disable_external_hpd();
omap_modeset_disable_external_hpd(ddev);
drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev);
err_cleanup_modeset:
drm_mode_config_cleanup(ddev);
omap_drm_irq_uninstall(ddev);
err_free_drm_dev:
err_gem_deinit:
omap_gem_deinit(ddev);
drm_dev_unref(ddev);
err_destroy_wq:
destroy_workqueue(priv->wq);
omap_disconnect_dssdevs();
omap_disconnect_pipelines(ddev);
err_crtc_uninit:
omap_crtc_pre_uninit();
omap_crtc_pre_uninit(priv);
drm_dev_unref(ddev);
return ret;
}
@ -618,7 +626,7 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
drm_dev_unregister(ddev);
omap_modeset_disable_external_hpd();
omap_modeset_disable_external_hpd(ddev);
drm_kms_helper_poll_fini(ddev);
omap_fbdev_fini(ddev);
@ -630,12 +638,12 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
omap_drm_irq_uninstall(ddev);
omap_gem_deinit(ddev);
drm_dev_unref(ddev);
destroy_workqueue(priv->wq);
omap_disconnect_dssdevs();
omap_crtc_pre_uninit();
omap_disconnect_pipelines(ddev);
omap_crtc_pre_uninit(priv);
drm_dev_unref(ddev);
}
static int pdev_probe(struct platform_device *pdev)
@ -677,36 +685,36 @@ static int pdev_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
static int omap_drm_suspend_all_displays(void)
static int omap_drm_suspend_all_displays(struct drm_device *ddev)
{
struct omap_dss_device *dssdev = NULL;
struct omap_drm_private *priv = ddev->dev_private;
int i;
for_each_dss_dev(dssdev) {
if (!dssdev->driver)
continue;
for (i = 0; i < priv->num_pipes; i++) {
struct omap_dss_device *display = priv->pipes[i].display;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
dssdev->driver->disable(dssdev);
dssdev->activate_after_resume = true;
if (display->state == OMAP_DSS_DISPLAY_ACTIVE) {
display->ops->disable(display);
display->activate_after_resume = true;
} else {
dssdev->activate_after_resume = false;
display->activate_after_resume = false;
}
}
return 0;
}
static int omap_drm_resume_all_displays(void)
static int omap_drm_resume_all_displays(struct drm_device *ddev)
{
struct omap_dss_device *dssdev = NULL;
struct omap_drm_private *priv = ddev->dev_private;
int i;
for_each_dss_dev(dssdev) {
if (!dssdev->driver)
continue;
for (i = 0; i < priv->num_pipes; i++) {
struct omap_dss_device *display = priv->pipes[i].display;
if (dssdev->activate_after_resume) {
dssdev->driver->enable(dssdev);
dssdev->activate_after_resume = false;
if (display->activate_after_resume) {
display->ops->enable(display);
display->activate_after_resume = false;
}
}
@ -721,7 +729,7 @@ static int omap_drm_suspend(struct device *dev)
drm_kms_helper_poll_disable(drm_dev);
drm_modeset_lock_all(drm_dev);
omap_drm_suspend_all_displays();
omap_drm_suspend_all_displays(drm_dev);
drm_modeset_unlock_all(drm_dev);
return 0;
@ -733,7 +741,7 @@ static int omap_drm_resume(struct device *dev)
struct drm_device *drm_dev = priv->ddev;
drm_modeset_lock_all(drm_dev);
omap_drm_resume_all_displays();
omap_drm_resume_all_displays(drm_dev);
drm_modeset_unlock_all(drm_dev);
drm_kms_helper_poll_enable(drm_dev);

View file

@ -45,6 +45,14 @@
struct omap_drm_usergart;
struct omap_drm_pipeline {
struct drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct omap_dss_device *output;
struct omap_dss_device *display;
};
struct omap_drm_private {
struct drm_device *ddev;
struct device *dev;
@ -54,18 +62,13 @@ struct omap_drm_private {
struct dispc_device *dispc;
const struct dispc_ops *dispc_ops;
unsigned int num_crtcs;
struct drm_crtc *crtcs[8];
unsigned int num_pipes;
struct omap_drm_pipeline pipes[8];
struct omap_drm_pipeline *channels[8];
unsigned int num_planes;
struct drm_plane *planes[8];
unsigned int num_encoders;
struct drm_encoder *encoders[8];
unsigned int num_connectors;
struct drm_connector *connectors[8];
struct drm_fb_helper *fbdev;
struct workqueue_struct *wq;

View file

@ -36,16 +36,10 @@
*/
struct omap_encoder {
struct drm_encoder base;
struct omap_dss_device *dssdev;
struct omap_dss_device *output;
struct omap_dss_device *display;
};
struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
{
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
return omap_encoder->dssdev;
}
static void omap_encoder_destroy(struct drm_encoder *encoder)
{
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
@ -59,16 +53,65 @@ static const struct drm_encoder_funcs omap_encoder_funcs = {
};
static void omap_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = encoder->dev;
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
struct omap_dss_device *dssdev = omap_encoder->dssdev;
struct drm_connector *connector;
struct omap_dss_device *dssdev;
struct videomode vm = { 0 };
bool hdmi_mode;
int r;
drm_display_mode_to_videomode(adjusted_mode, &vm);
/*
* HACK: This fixes the vm flags.
* struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
* they get lost when converting back and forth between struct
* drm_display_mode and struct videomode. The hack below goes and
* fetches the missing flags.
*
* A better solution is to use DRM's bus-flags through the whole driver.
*/
for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
unsigned long bus_flags = dssdev->bus_flags;
if (!(vm.flags & (DISPLAY_FLAGS_DE_LOW |
DISPLAY_FLAGS_DE_HIGH))) {
if (bus_flags & DRM_BUS_FLAG_DE_LOW)
vm.flags |= DISPLAY_FLAGS_DE_LOW;
else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
vm.flags |= DISPLAY_FLAGS_DE_HIGH;
}
if (!(vm.flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
else if (bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
}
if (!(vm.flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
DISPLAY_FLAGS_SYNC_NEGEDGE))) {
if (bus_flags & DRM_BUS_FLAG_SYNC_POSEDGE)
vm.flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
else if (bus_flags & DRM_BUS_FLAG_SYNC_NEGEDGE)
vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
}
}
/* Set timings for all devices in the display pipeline. */
dss_mgr_set_timings(omap_encoder->output, &vm);
for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
if (dssdev->ops->set_timings)
dssdev->ops->set_timings(dssdev, &vm);
}
/* Set the HDMI mode and HDMI infoframe if applicable. */
hdmi_mode = false;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
@ -77,73 +120,36 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
}
}
if (dssdev->driver->set_hdmi_mode)
dssdev->driver->set_hdmi_mode(dssdev, hdmi_mode);
dssdev = omap_encoder->output;
if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) {
if (dssdev->ops->hdmi.set_hdmi_mode)
dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) {
struct hdmi_avi_infoframe avi;
r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
false);
if (r == 0)
dssdev->driver->set_hdmi_infoframe(dssdev, &avi);
dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
}
}
static void omap_encoder_disable(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;
struct omap_dss_device *dssdev = omap_encoder->display;
dssdrv->disable(dssdev);
}
static int omap_encoder_update(struct drm_encoder *encoder,
enum omap_channel channel,
struct videomode *vm)
{
struct drm_device *dev = encoder->dev;
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 ret;
if (dssdrv->check_timings) {
ret = dssdrv->check_timings(dssdev, vm);
} else {
struct videomode t = {0};
dssdrv->get_timings(dssdev, &t);
if (memcmp(vm, &t, sizeof(*vm)))
ret = -EINVAL;
else
ret = 0;
}
if (ret) {
dev_err(dev->dev, "could not set timings: %d\n", ret);
return ret;
}
if (dssdrv->set_timings)
dssdrv->set_timings(dssdev, vm);
return 0;
dssdev->ops->disable(dssdev);
}
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;
struct omap_dss_device *dssdev = omap_encoder->display;
int r;
omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc),
omap_crtc_timings(encoder->crtc));
r = dssdrv->enable(dssdev);
r = dssdev->ops->enable(dssdev);
if (r)
dev_err(encoder->dev->dev,
"Failed to enable display '%s': %d\n",
@ -154,7 +160,36 @@ static int omap_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
return 0;
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
enum omap_channel channel = omap_encoder->output->dispc_channel;
struct drm_device *dev = encoder->dev;
struct omap_drm_private *priv = dev->dev_private;
struct omap_dss_device *dssdev;
struct videomode vm = { 0 };
int ret;
drm_display_mode_to_videomode(&crtc_state->mode, &vm);
ret = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
if (ret)
goto done;
for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
if (!dssdev->ops->check_timings)
continue;
ret = dssdev->ops->check_timings(dssdev, &vm);
if (ret)
goto done;
}
drm_display_mode_from_videomode(&vm, &crtc_state->adjusted_mode);
done:
if (ret)
dev_err(dev->dev, "invalid timings: %d\n", ret);
return ret;
}
static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
@ -166,7 +201,8 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
/* initialize encoder */
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
struct omap_dss_device *dssdev)
struct omap_dss_device *output,
struct omap_dss_device *display)
{
struct drm_encoder *encoder = NULL;
struct omap_encoder *omap_encoder;
@ -175,7 +211,8 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev,
if (!omap_encoder)
goto fail;
omap_encoder->dssdev = dssdev;
omap_encoder->output = output;
omap_encoder->display = display;
encoder = &omap_encoder->base;

View file

@ -25,9 +25,7 @@ struct drm_encoder;
struct omap_dss_device;
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
struct omap_dss_device *dssdev);
/* map crtc to vblank mask */
struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);
struct omap_dss_device *output,
struct omap_dss_device *display);
#endif /* __OMAPDRM_ENCODER_H__ */

View file

@ -243,7 +243,7 @@ void omap_fbdev_init(struct drm_device *dev)
struct drm_fb_helper *helper;
int ret = 0;
if (!priv->num_crtcs || !priv->num_connectors)
if (!priv->num_pipes)
return;
fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
@ -256,7 +256,7 @@ void omap_fbdev_init(struct drm_device *dev)
drm_fb_helper_prepare(dev, helper, &omap_fb_helper_funcs);
ret = drm_fb_helper_init(dev, helper, priv->num_connectors);
ret = drm_fb_helper_init(dev, helper, priv->num_pipes);
if (ret)
goto fail;

View file

@ -206,8 +206,8 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
VERB("irqs: %08x", irqstatus);
for (id = 0; id < priv->num_crtcs; id++) {
struct drm_crtc *crtc = priv->crtcs[id];
for (id = 0; id < priv->num_pipes; id++) {
struct drm_crtc *crtc = priv->pipes[id].crtc;
enum omap_channel channel = omap_crtc_channel(crtc);
if (irqstatus & priv->dispc_ops->mgr_get_vsync_irq(priv->dispc, channel)) {