aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/imx-drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/imx-drm')
-rw-r--r--drivers/staging/imx-drm/Kconfig12
-rw-r--r--drivers/staging/imx-drm/Makefile4
-rw-r--r--drivers/staging/imx-drm/TODO5
-rw-r--r--drivers/staging/imx-drm/imx-drm-core.c898
-rw-r--r--drivers/staging/imx-drm/imx-drm.h42
-rw-r--r--drivers/staging/imx-drm/imx-fb.c47
-rw-r--r--drivers/staging/imx-drm/imx-fbdev.c74
-rw-r--r--drivers/staging/imx-drm/imx-hdmi.c720
-rw-r--r--drivers/staging/imx-drm/imx-ldb.c149
-rw-r--r--drivers/staging/imx-drm/imx-tve.c132
-rw-r--r--drivers/staging/imx-drm/ipu-v3/Makefile3
-rw-r--r--drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h324
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-common.c1261
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dc.c412
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-di.c793
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c418
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dp.c338
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-prv.h206
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c117
-rw-r--r--drivers/staging/imx-drm/ipuv3-plane.c12
-rw-r--r--drivers/staging/imx-drm/parallel-display.c133
21 files changed, 957 insertions, 5143 deletions
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 78319ad176c..82fb758a29b 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -20,6 +20,7 @@ config DRM_IMX_FB_HELPER
config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
+ select DRM_PANEL
depends on DRM_IMX
select VIDEOMODE_HELPERS
@@ -38,19 +39,10 @@ config DRM_IMX_LDB
Choose this to enable the internal LVDS Display Bridge (LDB)
found on i.MX53 and i.MX6 processors.
-config DRM_IMX_IPUV3_CORE
- tristate "IPUv3 core support"
- depends on DRM_IMX
- depends on RESET_CONTROLLER
- help
- Choose this if you have a i.MX5/6 system and want
- to use the IPU. This option only enables IPU base
- support.
-
config DRM_IMX_IPUV3
tristate "DRM Support for i.MX IPUv3"
depends on DRM_IMX
- depends on DRM_IMX_IPUV3_CORE
+ depends on IMX_IPUV3_CORE
help
Choose this if you have a i.MX5 or i.MX6 processor.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 4677585b5ad..582c438d8cb 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,13 +1,11 @@
-imxdrm-objs := imx-drm-core.o imx-fb.o
+imxdrm-objs := imx-drm-core.o
obj-$(CONFIG_DRM_IMX) += imxdrm.o
obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
-obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
index 6a9da94c957..29636fb1395 100644
--- a/drivers/staging/imx-drm/TODO
+++ b/drivers/staging/imx-drm/TODO
@@ -1,15 +1,10 @@
TODO:
- get DRM Maintainer review for this code
-- Wait for common display framework to hit mainline and update the IPU
- driver to use it. This will most probably make changes to the devicetree
- bindings necessary.
-- Factor out more code to common helper functions
- decide where to put the base driver. It is not specific to a subsystem
and would be used by DRM/KMS and media/V4L2
Missing features (not necessarily for moving out of staging):
-- Add i.MX6 HDMI support
- Add support for IC (Image converter)
- Add support for CSI (CMOS Sensor interface)
- Add support for VDIC (Video Deinterlacer)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 09ef5fb8bae..def8280d7ee 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -13,14 +13,15 @@
* GNU General Public License for more details.
*
*/
-
+#include <linux/component.h>
#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
-#include <linux/module.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
@@ -28,45 +29,29 @@
#define MAX_CRTC 4
-struct crtc_cookie {
- void *cookie;
- int id;
+struct imx_drm_crtc;
+
+struct imx_drm_component {
+ struct device_node *of_node;
struct list_head list;
};
struct imx_drm_device {
struct drm_device *drm;
- struct device *dev;
- struct list_head crtc_list;
- struct list_head encoder_list;
- struct list_head connector_list;
- struct mutex mutex;
+ struct imx_drm_crtc *crtc[MAX_CRTC];
int pipes;
struct drm_fbdev_cma *fbhelper;
};
struct imx_drm_crtc {
struct drm_crtc *crtc;
- struct list_head list;
- struct imx_drm_device *imxdrm;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
- struct module *owner;
- struct crtc_cookie cookie;
+ struct device_node *port;
};
-struct imx_drm_encoder {
- struct drm_encoder *encoder;
- struct list_head list;
- struct module *owner;
- struct list_head possible_crtcs;
-};
-
-struct imx_drm_connector {
- struct drm_connector *connector;
- struct list_head list;
- struct module *owner;
-};
+static int legacyfb_depth = 16;
+module_param(legacyfb_depth, int, 0444);
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
@@ -76,95 +61,96 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
if (imxdrm->fbhelper)
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+#endif
}
static int imx_drm_driver_unload(struct drm_device *drm)
{
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
+#endif
- imx_drm_device_put();
+ drm_kms_helper_poll_fini(drm);
- drm_vblank_cleanup(imxdrm->drm);
- drm_kms_helper_poll_fini(imxdrm->drm);
- drm_mode_config_cleanup(imxdrm->drm);
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ if (imxdrm->fbhelper)
+ drm_fbdev_cma_fini(imxdrm->fbhelper);
+#endif
+
+ component_unbind_all(drm->dev, drm);
+
+ drm_vblank_cleanup(drm);
+ drm_mode_config_cleanup(drm);
return 0;
}
-/*
- * We don't care at all for crtc numbers, but the core expects the
- * crtcs to be numbered
- */
-static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
- int num)
+static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
{
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_device *imxdrm = crtc->dev->dev_private;
+ unsigned i;
+
+ for (i = 0; i < MAX_CRTC; i++)
+ if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+ return imxdrm->crtc[i];
- list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
- if (imx_drm_crtc->pipe == num)
- return imx_drm_crtc;
return NULL;
}
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
{
- struct imx_drm_device *imxdrm = crtc->dev->dev_private;
- struct imx_drm_crtc *imx_crtc;
struct imx_drm_crtc_helper_funcs *helper;
+ struct imx_drm_crtc *imx_crtc;
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
- if (imx_crtc->crtc == crtc)
- goto found;
+ imx_crtc = imx_drm_find_crtc(encoder->crtc);
+ if (!imx_crtc)
+ return -EINVAL;
- return -EINVAL;
-found:
helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt)
- return helper->set_interface_pix_fmt(crtc,
- encoder_type, interface_pix_fmt,
+ return helper->set_interface_pix_fmt(encoder->crtc,
+ encoder->encoder_type, interface_pix_fmt,
hsync_pin, vsync_pin);
return 0;
}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
- u32 interface_pix_fmt)
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
{
- return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
- interface_pix_fmt, 2, 3);
+ return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
}
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{
- return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+ return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
{
- drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+ drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
{
- drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+ drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
}
EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
{
struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
int ret;
- imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
if (!imx_drm_crtc)
return -EINVAL;
@@ -180,9 +166,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
{
struct imx_drm_device *imxdrm = drm->dev_private;
- struct imx_drm_crtc *imx_drm_crtc;
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
- imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
if (!imx_drm_crtc)
return;
@@ -215,195 +200,47 @@ static const struct file_operations imx_drm_driver_fops = {
.llseek = noop_llseek,
};
-static struct imx_drm_device *imx_drm_device;
-
-static struct imx_drm_device *__imx_drm_device(void)
-{
- return imx_drm_device;
-}
-
-struct drm_device *imx_drm_device_get(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *enc;
- struct imx_drm_connector *con;
- struct imx_drm_crtc *crtc;
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list) {
- if (!try_module_get(enc->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(enc->owner));
- goto unwind_enc;
- }
- }
-
- list_for_each_entry(con, &imxdrm->connector_list, list) {
- if (!try_module_get(con->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(con->owner));
- goto unwind_con;
- }
- }
-
- list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
- if (!try_module_get(crtc->owner)) {
- dev_err(imxdrm->dev, "could not get module %s\n",
- module_name(crtc->owner));
- goto unwind_crtc;
- }
- }
-
- return imxdrm->drm;
-
-unwind_crtc:
- list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
- module_put(crtc->owner);
-unwind_con:
- list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
- module_put(con->owner);
-unwind_enc:
- list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
- module_put(enc->owner);
-
- mutex_unlock(&imxdrm->mutex);
-
- return NULL;
-
-}
-EXPORT_SYMBOL_GPL(imx_drm_device_get);
-
-void imx_drm_device_put(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *enc;
- struct imx_drm_connector *con;
- struct imx_drm_crtc *crtc;
-
- mutex_lock(&imxdrm->mutex);
-
- list_for_each_entry(crtc, &imxdrm->crtc_list, list)
- module_put(crtc->owner);
-
- list_for_each_entry(con, &imxdrm->connector_list, list)
- module_put(con->owner);
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list)
- module_put(enc->owner);
-
- mutex_unlock(&imxdrm->mutex);
-}
-EXPORT_SYMBOL_GPL(imx_drm_device_put);
-
-static int drm_mode_group_reinit(struct drm_device *dev)
-{
- struct drm_mode_group *group = &dev->primary->mode_group;
- uint32_t *id_list = group->id_list;
- int ret;
-
- ret = drm_mode_group_init_legacy_group(dev, group);
- if (ret < 0)
- return ret;
-
- kfree(id_list);
- return 0;
-}
-
-/*
- * register an encoder to the drm core
- */
-static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
-
- drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
- imx_drm_encoder->encoder->funcs,
- imx_drm_encoder->encoder->encoder_type);
-
- drm_mode_group_reinit(imxdrm->drm);
-
- return 0;
-}
-
-/*
- * unregister an encoder from the drm core
- */
-static void imx_drm_encoder_unregister(struct imx_drm_encoder
- *imx_drm_encoder)
+void imx_drm_connector_destroy(struct drm_connector *connector)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_encoder_cleanup(imx_drm_encoder->encoder);
-
- drm_mode_group_reinit(imxdrm->drm);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
}
+EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
-/*
- * register a connector to the drm core
- */
-static int imx_drm_connector_register(
- struct imx_drm_connector *imx_drm_connector)
+void imx_drm_encoder_destroy(struct drm_encoder *encoder)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
- imx_drm_connector->connector->funcs,
- imx_drm_connector->connector->connector_type);
- drm_mode_group_reinit(imxdrm->drm);
-
- return drm_sysfs_connector_add(imx_drm_connector->connector);
+ drm_encoder_cleanup(encoder);
}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
-/*
- * unregister a connector from the drm core
- */
-static void imx_drm_connector_unregister(
- struct imx_drm_connector *imx_drm_connector)
+static void imx_drm_output_poll_changed(struct drm_device *drm)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- drm_sysfs_connector_remove(imx_drm_connector->connector);
- drm_connector_cleanup(imx_drm_connector->connector);
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ struct imx_drm_device *imxdrm = drm->dev_private;
- drm_mode_group_reinit(imxdrm->drm);
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+#endif
}
-/*
- * register a crtc to the drm core
- */
-static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- int ret;
-
- ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
- if (ret)
- return ret;
-
- drm_crtc_helper_add(imx_drm_crtc->crtc,
- imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
-
- drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
- imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
-
- drm_mode_group_reinit(imxdrm->drm);
-
- return 0;
-}
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = imx_drm_output_poll_changed,
+};
/*
- * Called by the CRTC driver when all CRTCs are registered. This
- * puts all the pieces together and initializes the driver.
- * Once this is called no more CRTCs can be registered since
- * the drm core has hardcoded the number of crtcs in several
- * places.
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
*/
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm;
+ struct drm_connector *connector;
int ret;
+ imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
+ if (!imxdrm)
+ return -ENOMEM;
+
imxdrm->drm = drm;
drm->dev_private = imxdrm;
@@ -419,139 +256,136 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
*/
drm->irq_enabled = true;
- drm_mode_config_init(drm);
- imx_drm_mode_config_init(drm);
-
- mutex_lock(&imxdrm->mutex);
+ /*
+ * set max width and height as default value(4096x4096).
+ * this value would be used to check framebuffer size limitation
+ * at drm_mode_addfb().
+ */
+ drm->mode_config.min_width = 64;
+ drm->mode_config.min_height = 64;
+ drm->mode_config.max_width = 4096;
+ drm->mode_config.max_height = 4096;
+ drm->mode_config.funcs = &imx_drm_mode_config_funcs;
- drm_kms_helper_poll_init(imxdrm->drm);
+ drm_mode_config_init(drm);
- /* setup the grouping for the legacy output */
- ret = drm_mode_group_init_legacy_group(imxdrm->drm,
- &imxdrm->drm->primary->mode_group);
+ ret = drm_vblank_init(drm, MAX_CRTC);
if (ret)
goto err_kms;
- ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+ /*
+ * with vblank_disable_allowed = true, vblank interrupt will be
+ * disabled by drm timer once a current process gives up ownership
+ * of vblank event. (after drm_vblank_put function is called)
+ */
+ drm->vblank_disable_allowed = true;
+
+ platform_set_drvdata(drm->platformdev, drm);
+
+ /* Now try and bind all our sub-components */
+ ret = component_bind_all(drm->dev, drm);
if (ret)
- goto err_kms;
+ goto err_vblank;
/*
- * with vblank_disable_allowed = true, vblank interrupt will be disabled
- * by drm timer once a current process gives up ownership of
- * vblank event.(after drm_vblank_put function is called)
+ * All components are now added, we can publish the connector sysfs
+ * entries to userspace. This will generate hotplug events and so
+ * userspace will expect to be able to access DRM at this point.
*/
- imxdrm->drm->vblank_disable_allowed = true;
+ list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+ ret = drm_sysfs_connector_add(connector);
+ if (ret) {
+ dev_err(drm->dev,
+ "[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n",
+ connector->base.id,
+ connector->name, ret);
+ goto err_unbind;
+ }
+ }
- if (!imx_drm_device_get()) {
- ret = -EINVAL;
- goto err_vblank;
+ /*
+ * All components are now initialised, so setup the fb helper.
+ * The fb helper takes copies of key hardware information, so the
+ * crtcs/connectors/encoders must not change after this point.
+ */
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+ dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
+ legacyfb_depth = 16;
}
+ imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+ drm->mode_config.num_crtc, MAX_CRTC);
+ if (IS_ERR(imxdrm->fbhelper)) {
+ ret = PTR_ERR(imxdrm->fbhelper);
+ imxdrm->fbhelper = NULL;
+ goto err_unbind;
+ }
+#endif
+
+ drm_kms_helper_poll_init(drm);
- platform_set_drvdata(drm->platformdev, drm);
- mutex_unlock(&imxdrm->mutex);
return 0;
+err_unbind:
+ component_unbind_all(drm->dev, drm);
err_vblank:
drm_vblank_cleanup(drm);
err_kms:
- drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
- mutex_unlock(&imxdrm->mutex);
return ret;
}
-static void imx_drm_update_possible_crtcs(void)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_crtc *imx_drm_crtc;
- struct imx_drm_encoder *enc;
- struct crtc_cookie *cookie;
-
- list_for_each_entry(enc, &imxdrm->encoder_list, list) {
- u32 possible_crtcs = 0;
-
- list_for_each_entry(cookie, &enc->possible_crtcs, list) {
- list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
- if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
- imx_drm_crtc->cookie.id == cookie->id) {
- possible_crtcs |= 1 << imx_drm_crtc->pipe;
- }
- }
- }
- enc->encoder->possible_crtcs = possible_crtcs;
- enc->encoder->possible_clones = possible_crtcs;
- }
-}
-
/*
* imx_drm_add_crtc - add a new crtc
- *
- * The return value if !NULL is a cookie for the caller to pass to
- * imx_drm_remove_crtc later.
*/
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc,
const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
- struct module *owner, void *cookie, int id)
+ struct device_node *port)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
+ struct imx_drm_device *imxdrm = drm->dev_private;
struct imx_drm_crtc *imx_drm_crtc;
int ret;
- mutex_lock(&imxdrm->mutex);
-
/*
* The vblank arrays are dimensioned by MAX_CRTC - we can't
* pass IDs greater than this to those functions.
*/
- if (imxdrm->pipes >= MAX_CRTC) {
- ret = -EINVAL;
- goto err_busy;
- }
+ if (imxdrm->pipes >= MAX_CRTC)
+ return -EINVAL;
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
+ if (imxdrm->drm->open_count)
+ return -EBUSY;
imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
- if (!imx_drm_crtc) {
- ret = -ENOMEM;
- goto err_alloc;
- }
+ if (!imx_drm_crtc)
+ return -ENOMEM;
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
imx_drm_crtc->pipe = imxdrm->pipes++;
- imx_drm_crtc->cookie.cookie = cookie;
- imx_drm_crtc->cookie.id = id;
-
+ imx_drm_crtc->port = port;
imx_drm_crtc->crtc = crtc;
- imx_drm_crtc->imxdrm = imxdrm;
-
- imx_drm_crtc->owner = owner;
- list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
*new_crtc = imx_drm_crtc;
- ret = imx_drm_crtc_register(imx_drm_crtc);
+ ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
if (ret)
goto err_register;
- imx_drm_update_possible_crtcs();
+ drm_crtc_helper_add(crtc,
+ imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
- mutex_unlock(&imxdrm->mutex);
+ drm_crtc_init(drm, crtc,
+ imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
return 0;
err_register:
- list_del(&imx_drm_crtc->list);
+ imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
kfree(imx_drm_crtc);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -561,17 +395,11 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
*/
int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
{
- struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
-
- mutex_lock(&imxdrm->mutex);
+ struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
drm_crtc_cleanup(imx_drm_crtc->crtc);
- list_del(&imx_drm_crtc->list);
-
- drm_mode_group_reinit(imxdrm->drm);
-
- mutex_unlock(&imxdrm->mutex);
+ imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
kfree(imx_drm_crtc);
@@ -580,220 +408,115 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
/*
- * imx_drm_add_encoder - add a new encoder
+ * Find the DRM CRTC possible mask for the connected endpoint.
+ *
+ * The encoder possible masks are defined by their position in the
+ * mode_config crtc_list. This means that CRTCs must not be added
+ * or removed once the DRM device has been fully initialised.
*/
-int imx_drm_add_encoder(struct drm_encoder *encoder,
- struct imx_drm_encoder **newenc, struct module *owner)
+static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
+ struct device_node *endpoint)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_encoder *imx_drm_encoder;
- int ret;
-
- mutex_lock(&imxdrm->mutex);
+ struct device_node *port;
+ unsigned i;
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
-
- imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
- if (!imx_drm_encoder) {
- ret = -ENOMEM;
- goto err_alloc;
- }
+ port = of_graph_get_remote_port(endpoint);
+ if (!port)
+ return 0;
+ of_node_put(port);
- imx_drm_encoder->encoder = encoder;
- imx_drm_encoder->owner = owner;
-
- ret = imx_drm_encoder_register(imx_drm_encoder);
- if (ret) {
- ret = -ENOMEM;
- goto err_register;
+ for (i = 0; i < MAX_CRTC; i++) {
+ struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+ if (imx_drm_crtc && imx_drm_crtc->port == port)
+ return drm_crtc_mask(imx_drm_crtc->crtc);
}
- list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
-
- *newenc = imx_drm_encoder;
-
- mutex_unlock(&imxdrm->mutex);
-
return 0;
+}
-err_register:
- kfree(imx_drm_encoder);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
-
- return ret;
+static struct device_node *imx_drm_of_get_next_endpoint(
+ const struct device_node *parent, struct device_node *prev)
+{
+ struct device_node *node = of_graph_get_next_endpoint(parent, prev);
+ of_node_put(prev);
+ return node;
}
-EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
-int imx_drm_encoder_add_possible_crtcs(
- struct imx_drm_encoder *imx_drm_encoder,
- struct device_node *np)
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct of_phandle_args args;
- struct crtc_cookie *c;
- int ret = 0;
+ struct imx_drm_device *imxdrm = drm->dev_private;
+ struct device_node *ep = NULL;
+ uint32_t crtc_mask = 0;
int i;
- if (!list_empty(&imx_drm_encoder->possible_crtcs))
- return -EBUSY;
+ for (i = 0; ; i++) {
+ u32 mask;
- for (i = 0; !ret; i++) {
- ret = of_parse_phandle_with_args(np, "crtcs",
- "#crtc-cells", i, &args);
- if (ret < 0)
+ ep = imx_drm_of_get_next_endpoint(np, ep);
+ if (!ep)
break;
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c) {
- of_node_put(args.np);
- return -ENOMEM;
- }
-
- c->cookie = args.np;
- c->id = args.args_count > 0 ? args.args[0] : 0;
-
- of_node_put(args.np);
+ mask = imx_drm_find_crtc_mask(imxdrm, ep);
- mutex_lock(&imxdrm->mutex);
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (mask == 0)
+ return -EPROBE_DEFER;
- list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
-
- mutex_unlock(&imxdrm->mutex);
+ crtc_mask |= mask;
}
- imx_drm_update_possible_crtcs();
+ if (ep)
+ of_node_put(ep);
+ if (i == 0)
+ return -ENOENT;
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
+ encoder->possible_crtcs = crtc_mask;
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
- struct drm_crtc *crtc)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_crtc *imx_crtc;
- int i = 0;
-
- list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
- if (imx_crtc->crtc == crtc)
- goto found;
- i++;
- }
-
- return -EINVAL;
-found:
- return i;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
-
-/*
- * imx_drm_remove_encoder - remove an encoder
- */
-int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct crtc_cookie *c, *tmp;
-
- mutex_lock(&imxdrm->mutex);
-
- imx_drm_encoder_unregister(imx_drm_encoder);
-
- list_del(&imx_drm_encoder->list);
-
- list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
- list)
- kfree(c);
-
- mutex_unlock(&imxdrm->mutex);
-
- kfree(imx_drm_encoder);
+ /* FIXME: this is the mask of outputs which can clone this output. */
+ encoder->possible_clones = ~0;
return 0;
}
-EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
/*
- * imx_drm_add_connector - add a connector
+ * @node: device tree node containing encoder input ports
+ * @encoder: drm_encoder
*/
-int imx_drm_add_connector(struct drm_connector *connector,
- struct imx_drm_connector **new_con,
- struct module *owner)
+int imx_drm_encoder_get_mux_id(struct device_node *node,
+ struct drm_encoder *encoder)
{
- struct imx_drm_device *imxdrm = __imx_drm_device();
- struct imx_drm_connector *imx_drm_connector;
+ struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
+ struct device_node *ep = NULL;
+ struct of_endpoint endpoint;
+ struct device_node *port;
int ret;
- mutex_lock(&imxdrm->mutex);
-
- if (imxdrm->drm->open_count) {
- ret = -EBUSY;
- goto err_busy;
- }
-
- imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
- if (!imx_drm_connector) {
- ret = -ENOMEM;
- goto err_alloc;
- }
-
- imx_drm_connector->connector = connector;
- imx_drm_connector->owner = owner;
-
- ret = imx_drm_connector_register(imx_drm_connector);
- if (ret)
- goto err_register;
-
- list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
-
- *new_con = imx_drm_connector;
-
- mutex_unlock(&imxdrm->mutex);
-
- return 0;
-
-err_register:
- kfree(imx_drm_connector);
-err_alloc:
-err_busy:
- mutex_unlock(&imxdrm->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_connector);
-
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- imxdrm->fbhelper = fbdev_helper;
-}
-EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
-
-/*
- * imx_drm_remove_connector - remove a connector
- */
-int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
-{
- struct imx_drm_device *imxdrm = __imx_drm_device();
-
- mutex_lock(&imxdrm->mutex);
-
- imx_drm_connector_unregister(imx_drm_connector);
-
- list_del(&imx_drm_connector->list);
+ if (!node || !imx_crtc)
+ return -EINVAL;
- mutex_unlock(&imxdrm->mutex);
+ do {
+ ep = imx_drm_of_get_next_endpoint(node, ep);
+ if (!ep)
+ break;
- kfree(imx_drm_connector);
+ port = of_graph_get_remote_port(ep);
+ of_node_put(port);
+ if (port == imx_crtc->port) {
+ ret = of_graph_parse_endpoint(ep, &endpoint);
+ return ret ? ret : endpoint.port;
+ }
+ } while (ep);
- return 0;
+ return -EINVAL;
}
-EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
+EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
static const struct drm_ioctl_desc imx_drm_ioctls[] = {
/* none so far */
@@ -834,80 +557,161 @@ static struct drm_driver imx_drm_driver = {
.patchlevel = 0,
};
-static int imx_drm_platform_probe(struct platform_device *pdev)
+static int compare_of(struct device *dev, void *data)
{
- int ret;
+ struct device_node *np = data;
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- imx_drm_device->dev = &pdev->dev;
+ /* Special case for LDB, one device for two channels */
+ if (of_node_cmp(np->name, "lvds-channel") == 0) {
+ np = of_get_parent(np);
+ of_node_put(np);
+ }
- return drm_platform_init(&imx_drm_driver, pdev);
+ return dev->of_node == np;
}
-static int imx_drm_platform_remove(struct platform_device *pdev)
+static LIST_HEAD(imx_drm_components);
+
+static int imx_drm_add_components(struct device *master, struct master *m)
{
- drm_put_dev(platform_get_drvdata(pdev));
+ struct imx_drm_component *component;
+ int ret;
+ list_for_each_entry(component, &imx_drm_components, list) {
+ ret = component_master_add_child(m, compare_of,
+ component->of_node);
+ if (ret)
+ return ret;
+ }
return 0;
}
-static struct platform_driver imx_drm_pdrv = {
- .probe = imx_drm_platform_probe,
- .remove = imx_drm_platform_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "imx-drm",
- },
+static int imx_drm_bind(struct device *dev)
+{
+ return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+ drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+ .add_components = imx_drm_add_components,
+ .bind = imx_drm_bind,
+ .unbind = imx_drm_unbind,
};
-static struct platform_device *imx_drm_pdev;
+static struct imx_drm_component *imx_drm_find_component(struct device *dev,
+ struct device_node *node)
+{
+ struct imx_drm_component *component;
+
+ list_for_each_entry(component, &imx_drm_components, list)
+ if (component->of_node == node)
+ return component;
+
+ return NULL;
+}
-static int __init imx_drm_init(void)
+static int imx_drm_add_component(struct device *dev, struct device_node *node)
{
- int ret;
+ struct imx_drm_component *component;
+
+ if (imx_drm_find_component(dev, node))
+ return 0;
- imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
- if (!imx_drm_device)
+ component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
+ if (!component)
return -ENOMEM;
- mutex_init(&imx_drm_device->mutex);
- INIT_LIST_HEAD(&imx_drm_device->crtc_list);
- INIT_LIST_HEAD(&imx_drm_device->connector_list);
- INIT_LIST_HEAD(&imx_drm_device->encoder_list);
+ component->of_node = node;
+ list_add_tail(&component->list, &imx_drm_components);
- imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
- if (IS_ERR(imx_drm_pdev)) {
- ret = PTR_ERR(imx_drm_pdev);
- goto err_pdev;
+ return 0;
+}
+
+static int imx_drm_platform_probe(struct platform_device *pdev)
+{
+ struct device_node *ep, *port, *remote;
+ int ret;
+ int i;
+
+ /*
+ * Bind the IPU display interface ports first, so that
+ * imx_drm_encoder_parse_of called from encoder .bind callbacks
+ * works as expected.
+ */
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(pdev->dev.of_node, "ports", i);
+ if (!port)
+ break;
+
+ ret = imx_drm_add_component(&pdev->dev, port);
+ if (ret < 0)
+ return ret;
}
- ret = platform_driver_register(&imx_drm_pdrv);
- if (ret)
- goto err_pdrv;
+ if (i == 0) {
+ dev_err(&pdev->dev, "missing 'ports' property\n");
+ return -ENODEV;
+ }
- return 0;
+ /* Then bind all encoders */
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(pdev->dev.of_node, "ports", i);
+ if (!port)
+ break;
-err_pdrv:
- platform_device_unregister(imx_drm_pdev);
-err_pdev:
- kfree(imx_drm_device);
+ for_each_child_of_node(port, ep) {
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote || !of_device_is_available(remote)) {
+ of_node_put(remote);
+ continue;
+ } else if (!of_device_is_available(remote->parent)) {
+ dev_warn(&pdev->dev, "parent device of %s is not available\n",
+ remote->full_name);
+ of_node_put(remote);
+ continue;
+ }
- return ret;
+ ret = imx_drm_add_component(&pdev->dev, remote);
+ of_node_put(remote);
+ if (ret < 0)
+ return ret;
+ }
+ of_node_put(port);
+ }
+
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ return component_master_add(&pdev->dev, &imx_drm_ops);
}
-static void __exit imx_drm_exit(void)
+static int imx_drm_platform_remove(struct platform_device *pdev)
{
- platform_device_unregister(imx_drm_pdev);
- platform_driver_unregister(&imx_drm_pdrv);
-
- kfree(imx_drm_device);
+ component_master_del(&pdev->dev, &imx_drm_ops);
+ return 0;
}
-module_init(imx_drm_init);
-module_exit(imx_drm_exit);
+static const struct of_device_id imx_drm_dt_ids[] = {
+ { .compatible = "fsl,imx-display-subsystem", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
+static struct platform_driver imx_drm_pdrv = {
+ .probe = imx_drm_platform_probe,
+ .remove = imx_drm_platform_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "imx-drm",
+ .of_match_table = imx_drm_dt_ids,
+ },
+};
+module_platform_driver(imx_drm_pdrv);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX drm driver core");
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae90c9c1531..7453ae00c41 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -1,17 +1,15 @@
#ifndef _IMX_DRM_H_
#define _IMX_DRM_H_
-#include <linux/videodev2.h>
-
-#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3')
-
+struct device_node;
struct drm_crtc;
struct drm_connector;
struct drm_device;
+struct drm_display_mode;
struct drm_encoder;
-struct imx_drm_crtc;
struct drm_fbdev_cma;
struct drm_framebuffer;
+struct imx_drm_crtc;
struct platform_device;
int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
@@ -25,10 +23,10 @@ struct imx_drm_crtc_helper_funcs {
const struct drm_crtc_funcs *crtc_funcs;
};
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
struct imx_drm_crtc **new_crtc,
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
- struct module *owner, void *cookie, int id);
+ struct device_node *port);
int imx_drm_remove_crtc(struct imx_drm_crtc *);
int imx_drm_init_drm(struct platform_device *pdev,
int preferred_bpp);
@@ -38,35 +36,21 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
-struct imx_drm_encoder;
-int imx_drm_add_encoder(struct drm_encoder *encoder,
- struct imx_drm_encoder **new_enc,
- struct module *owner);
-int imx_drm_remove_encoder(struct imx_drm_encoder *);
-
-struct imx_drm_connector;
-int imx_drm_add_connector(struct drm_connector *connector,
- struct imx_drm_connector **new_con,
- struct module *owner);
-int imx_drm_remove_connector(struct imx_drm_connector *);
-
void imx_drm_mode_config_init(struct drm_device *drm);
struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
-struct drm_device *imx_drm_device_get(void);
-void imx_drm_device_put(void);
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format(struct drm_encoder *encoder,
u32 interface_pix_fmt);
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
-struct device_node;
+int imx_drm_encoder_get_mux_id(struct device_node *node,
+ struct drm_encoder *encoder);
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np);
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
- struct drm_crtc *crtc);
-int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
- struct device_node *np);
+void imx_drm_connector_destroy(struct drm_connector *connector);
+void imx_drm_encoder_destroy(struct drm_encoder *encoder);
#endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c
deleted file mode 100644
index 03a7b4e14f6..00000000000
--- a/drivers/staging/imx-drm/imx-fb.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
- .fb_create = drm_fb_cma_create,
-};
-
-void imx_drm_mode_config_init(struct drm_device *dev)
-{
- dev->mode_config.min_width = 64;
- dev->mode_config.min_height = 64;
-
- /*
- * set max width and height as default value(4096x4096).
- * this value would be used to check framebuffer size limitation
- * at drm_mode_addfb().
- */
- dev->mode_config.max_width = 4096;
- dev->mode_config.max_height = 4096;
-
- dev->mode_config.funcs = &imx_drm_mode_config_funcs;
-}
diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c
deleted file mode 100644
index 8331739c3d0..00000000000
--- a/drivers/staging/imx-drm/imx-fbdev.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-#define MAX_CONNECTOR 4
-#define PREFERRED_BPP 16
-
-static struct drm_fbdev_cma *fbdev_cma;
-
-static int legacyfb_depth = 16;
-
-module_param(legacyfb_depth, int, 0444);
-
-static int __init imx_fb_helper_init(void)
-{
- struct drm_device *drm = imx_drm_device_get();
-
- if (!drm)
- return -EINVAL;
-
- if (legacyfb_depth != 16 && legacyfb_depth != 32) {
- pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
- legacyfb_depth = 16;
- }
-
- fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
- drm->mode_config.num_crtc, MAX_CONNECTOR);
-
- if (IS_ERR(fbdev_cma)) {
- imx_drm_device_put();
- return PTR_ERR(fbdev_cma);
- }
-
- imx_drm_fb_helper_set(fbdev_cma);
-
- return 0;
-}
-
-static void __exit imx_fb_helper_exit(void)
-{
- imx_drm_fb_helper_set(NULL);
- drm_fbdev_cma_fini(fbdev_cma);
- imx_drm_device_put();
-}
-
-late_initcall(imx_fb_helper_init);
-module_exit(imx_fb_helper_exit);
-
-MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index f3a1f5e2e49..18c9ccd460b 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -12,10 +12,12 @@
* Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*/
+#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/hdmi.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -25,8 +27,8 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include <video/imx-ipu-v3.h>
-#include "ipu-v3/imx-ipu-v3.h"
#include "imx-hdmi.h"
#include "imx-drm.h"
@@ -52,11 +54,6 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
-enum hdmi_colorimetry {
- ITU601,
- ITU709,
-};
-
enum imx_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
@@ -116,9 +113,7 @@ struct hdmi_data_info {
struct imx_hdmi {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
enum imx_hdmi_devtype dev_type;
struct device *dev;
@@ -138,7 +133,6 @@ struct imx_hdmi {
struct i2c_adapter *ddc;
void __iomem *regs;
- unsigned long pixel_clk_rate;
unsigned int sample_rate;
int ratio;
};
@@ -160,37 +154,35 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
return readb(hdmi->regs + offset);
}
+static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+ u8 val = hdmi_readb(hdmi, reg) & ~mask;
+
+ val |= data & mask;
+ hdmi_writeb(hdmi, val, reg);
+}
+
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
- u8 value = hdmi_readb(hdmi, reg) & ~mask;
- value |= (data << shift) & mask;
- hdmi_writeb(hdmi, value, reg);
+ hdmi_modb(hdmi, data << shift, mask, reg);
}
static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
unsigned int value)
{
- u8 val;
-
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
/* nshift factor = 0 */
- val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
- val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
- hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
{
- u8 val;
-
/* Must be set/cleared first */
- val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
- val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
- hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
@@ -335,34 +327,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
-{
- unsigned long rate;
-
- rate = 65000000; /* FIXME */
-
- if (rate)
- hdmi->pixel_clk_rate = rate;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
- clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+ clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+ clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
hdmi->ratio);
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, hdmi->pixel_clk_rate);
+ __func__, pixel_clk);
return;
}
dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
__func__, hdmi->sample_rate, hdmi->ratio,
- hdmi->pixel_clk_rate, clk_n, clk_cts);
+ pixel_clk, clk_n, clk_cts);
hdmi_set_clock_regenerator_n(hdmi, clk_n);
hdmi_regenerate_cts(hdmi, clk_cts);
@@ -370,32 +353,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
{
- unsigned int clk_n, clk_cts;
-
- clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
- hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
- hdmi->ratio);
-
- if (!clk_cts) {
- dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, hdmi->pixel_clk_rate);
- return;
- }
-
- dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
- __func__, hdmi->sample_rate, hdmi->ratio,
- hdmi->pixel_clk_rate, clk_n, clk_cts);
-
- hdmi_set_clock_regenerator_n(hdmi, clk_n);
- hdmi_regenerate_cts(hdmi, clk_cts);
+ hdmi_set_clk_regenerator(hdmi, 74250000);
}
static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
{
- /* Get pixel clock from ipu */
- hdmi_get_pixel_clk(hdmi);
- hdmi_set_clk_regenerator(hdmi);
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
/*
@@ -463,38 +426,45 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
static int is_color_space_conversion(struct imx_hdmi *hdmi)
{
- return (hdmi->hdmi_data.enc_in_format !=
- hdmi->hdmi_data.enc_out_format);
+ return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
static int is_color_space_decimation(struct imx_hdmi *hdmi)
{
- return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) &&
- (hdmi->hdmi_data.enc_in_format == RGB ||
- hdmi->hdmi_data.enc_in_format == YCBCR444));
+ if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+ return 0;
+ if (hdmi->hdmi_data.enc_in_format == RGB ||
+ hdmi->hdmi_data.enc_in_format == YCBCR444)
+ return 1;
+ return 0;
}
static int is_color_space_interpolation(struct imx_hdmi *hdmi)
{
- return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) &&
- (hdmi->hdmi_data.enc_out_format == RGB ||
- hdmi->hdmi_data.enc_out_format == YCBCR444));
+ if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+ return 0;
+ if (hdmi->hdmi_data.enc_out_format == RGB ||
+ hdmi->hdmi_data.enc_out_format == YCBCR444)
+ return 1;
+ return 0;
}
static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+ unsigned i;
u32 csc_scale = 1;
- u8 val;
if (is_color_space_conversion(hdmi)) {
if (hdmi->hdmi_data.enc_out_format == RGB) {
- if (hdmi->hdmi_data.colorimetry == ITU601)
+ if (hdmi->hdmi_data.colorimetry ==
+ HDMI_COLORIMETRY_ITU_601)
csc_coeff = &csc_coeff_rgb_out_eitu601;
else
csc_coeff = &csc_coeff_rgb_out_eitu709;
} else if (hdmi->hdmi_data.enc_in_format == RGB) {
- if (hdmi->hdmi_data.colorimetry == ITU601)
+ if (hdmi->hdmi_data.colorimetry ==
+ HDMI_COLORIMETRY_ITU_601)
csc_coeff = &csc_coeff_rgb_in_eitu601;
else
csc_coeff = &csc_coeff_rgb_in_eitu709;
@@ -502,37 +472,24 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
}
}
- hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
-
- hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
-
- hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
- hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
-
- val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
- val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
- val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
- hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+ /* The CSC registers are sequential, alternating MSB then LSB */
+ for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+ u16 coeff_a = (*csc_coeff)[0][i];
+ u16 coeff_b = (*csc_coeff)[1][i];
+ u16 coeff_c = (*csc_coeff)[2][i];
+
+ hdmi_writeb(hdmi, coeff_a & 0xff,
+ HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff,
+ HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+ }
+
+ hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+ HDMI_CSC_SCALE);
}
static void hdmi_video_csc(struct imx_hdmi *hdmi)
@@ -540,7 +497,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
int decimation = 0;
- u8 val;
/* YCC422 interpolation to 444 mode */
if (is_color_space_interpolation(hdmi))
@@ -561,10 +517,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
/* Configure the CSC registers */
hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
- val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
- val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
- val |= color_depth;
- hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+ hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+ HDMI_CSC_SCALE);
imx_hdmi_update_csc_coeffs(hdmi);
}
@@ -580,7 +534,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
- u8 val;
+ u8 val, vp_conf;
if (hdmi_data->enc_out_format == RGB
|| hdmi_data->enc_out_format == YCBCR444) {
@@ -619,107 +573,75 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
- val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
/* Data from pixel repeater block */
if (hdmi_data->pix_repet_factor > 1) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_ENABLE |
- HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
} else { /* data from packetizer block */
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK);
- val |= HDMI_VP_CONF_PR_EN_DISABLE |
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
}
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
- val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
+ hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+ HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_ENABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_ENABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
- HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK);
- val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
} else {
return;
}
- val = hdmi_readb(hdmi, HDMI_VP_STUFF);
- val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
- HDMI_VP_STUFF_YCC422_STUFFING_MASK);
- val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
- HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
- hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
- val = hdmi_readb(hdmi, HDMI_VP_CONF);
- val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
- val |= output_select;
- hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+ hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+ HDMI_VP_CONF);
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
- HDMI_PHY_TST0_TSTCLR_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+ HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTEN_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
- HDMI_PHY_TST0_TSTEN_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+ HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
unsigned char bit)
{
- u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
- val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
- val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
- HDMI_PHY_TST0_TSTCLK_MASK;
- hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+ HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
@@ -736,13 +658,10 @@ static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
{
- unsigned char val = 0;
- val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3;
- while (!val) {
- udelay(1000);
+ while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
- val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3;
+ udelay(1000);
}
return true;
}
@@ -810,19 +729,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+static const struct mpll_config mpll_config[] = {
+ {
+ 45250000, {
+ { 0x01e0, 0x0000 },
+ { 0x21e1, 0x0000 },
+ { 0x41e2, 0x0000 }
+ },
+ }, {
+ 92500000, {
+ { 0x0140, 0x0005 },
+ { 0x2141, 0x0005 },
+ { 0x4142, 0x0005 },
+ },
+ }, {
+ 148500000, {
+ { 0x00a0, 0x000a },
+ { 0x20a1, 0x000a },
+ { 0x40a2, 0x000a },
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+static const struct curr_ctrl curr_ctrl[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ {
+ 54000000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 58400000, { 0x091c, 0x06dc, 0x06dc },
+ }, {
+ 72000000, { 0x06dc, 0x06dc, 0x091c },
+ }, {
+ 74250000, { 0x06dc, 0x0b5c, 0x091c },
+ }, {
+ 118800000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 216000000, { 0x06dc, 0x0b5c, 0x091c },
+ }
+};
+
static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
+ unsigned res_idx, i;
u8 val, msec;
- /* color resolution 0 is 8 bit colour depth */
- if (!res)
- res = 8;
-
if (prep)
return -EINVAL;
- else if (res != 8 && res != 12)
+
+ switch (res) {
+ case 0: /* color resolution 0 is 8 bit colour depth */
+ case 8:
+ res_idx = RES_8;
+ break;
+ case 10:
+ res_idx = RES_10;
+ break;
+ case 12:
+ res_idx = RES_12;
+ break;
+ default:
return -EINVAL;
+ }
/* Enable csc path */
if (cscon)
@@ -849,165 +843,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
- switch (res) {
- case 8:
- /* PLL/MPLL Cfg */
- hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ /* PLL/MPLL Cfg - always match on final entry */
+ for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ mpll_config[i].mpixelclock)
break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- default:
- return -EINVAL;
- }
- } else {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
- hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
- default:
- return -EINVAL;
- }
- }
- if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- default:
- return -EINVAL;
- }
- } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
- switch (res) {
- case 8:
- hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
- break;
- case 10:
- hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
- break;
- case 12:
- hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+ for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ curr_ctrl[i].mpixelclock)
break;
- default:
- return -EINVAL;
- }
- } else {
+
+ if (i >= ARRAY_SIZE(curr_ctrl)) {
dev_err(hdmi->dev,
"Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
+ /* CURRCTRL */
+ hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
/* RESISTANCE TERM 133Ohm Cfg */
@@ -1076,7 +935,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
{
- u8 de, val;
+ u8 de;
if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
@@ -1084,20 +943,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
/* disable rx detect */
- val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
- val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
- val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+ HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
- val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
- val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
- val |= de;
- hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+ hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
- val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
- val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
- val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
- hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
static void hdmi_config_AVI(struct imx_hdmi *hdmi)
@@ -1140,16 +992,16 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
/* Set up colorimetry */
if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
- if (hdmi->hdmi_data.colorimetry == ITU601)
+ if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
ext_colorimetry =
HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
- else /* hdmi->hdmi_data.colorimetry == ITU709 */
+ else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
ext_colorimetry =
HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
} else if (hdmi->hdmi_data.enc_out_format != RGB) {
- if (hdmi->hdmi_data.colorimetry == ITU601)
+ if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
- else /* hdmi->hdmi_data.colorimetry == ITU709 */
+ else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
} else { /* Carries no data */
@@ -1321,11 +1173,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
{
- u8 clkdis;
-
- clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
- clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
@@ -1379,9 +1227,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
(hdmi->vic == 21) || (hdmi->vic == 22) ||
(hdmi->vic == 2) || (hdmi->vic == 3) ||
(hdmi->vic == 17) || (hdmi->vic == 18))
- hdmi->hdmi_data.colorimetry = ITU601;
+ hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
else
- hdmi->hdmi_data.colorimetry = ITU709;
+ hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
(hdmi->vic == 12) || (hdmi->vic == 13) ||
@@ -1460,9 +1308,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
return 0;
}
@@ -1531,12 +1376,11 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- /* FIXME */
- return connector_status_connected;
-}
+ struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ connector);
-static void imx_hdmi_connector_destroy(struct drm_connector *connector)
-{
+ return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+ connector_status_connected : connector_status_disconnected;
}
static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1564,13 +1408,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
-
- return MODE_OK;
-}
-
static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1618,28 +1455,21 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
- V4L2_PIX_FMT_RGB24);
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
{
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
- int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
imx_hdmi_set_ipu_di_mux(hdmi, mux);
imx_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
-{
- return;
-}
-
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_hdmi_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1655,21 +1485,31 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
.get_modes = imx_hdmi_connector_get_modes,
- .mode_valid = imx_hdmi_connector_mode_valid,
.best_encoder = imx_hdmi_connector_best_encoder,
};
+static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+{
+ struct imx_hdmi *hdmi = dev_id;
+ u8 intr_stat;
+
+ intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+ if (intr_stat)
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
{
struct imx_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
- u8 val;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1679,55 +1519,45 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");
- val = hdmi_readb(hdmi, HDMI_PHY_POL0);
- val &= ~HDMI_PHY_HPD;
- hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+ hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
imx_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
- val = hdmi_readb(hdmi, HDMI_PHY_POL0);
- val |= HDMI_PHY_HPD;
- hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+ hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
+ HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct imx_hdmi *hdmi)
+static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
int ret;
- hdmi->connector.funcs = &imx_hdmi_connector_funcs;
- hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
+ ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
+ hdmi->dev->of_node);
+ if (ret)
+ return ret;
- hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
- hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
&imx_hdmi_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&hdmi->connector,
- &hdmi->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(hdmi->imx_drm_encoder);
- dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1754,28 +1584,33 @@ static const struct of_device_id imx_hdmi_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
+ struct platform_device *pdev = to_platform_device(dev);
const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, &pdev->dev);
- struct device_node *np = pdev->dev.of_node;
+ of_match_device(imx_hdmi_dt_ids, dev);
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
if (of_id) {
const struct platform_device_id *device_id = of_id->data;
+
hdmi->dev_type = device_id->driver_data;
}
- ddc_node = of_parse_phandle(np, "ddc", 0);
+ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
if (!hdmi->ddc)
@@ -1788,15 +1623,16 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return -EINVAL;
+ return irq;
- ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
- dev_name(&pdev->dev), hdmi);
+ ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
+ imx_hdmi_irq, IRQF_SHARED,
+ dev_name(dev), hdmi);
if (ret)
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+ hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
@@ -1835,7 +1671,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
}
/* Product and revision IDs */
- dev_info(&pdev->dev,
+ dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
hdmi_readb(hdmi, HDMI_DESIGN_ID),
hdmi_readb(hdmi, HDMI_REVISION_ID),
@@ -1863,13 +1699,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
if (ret)
goto err_iahb;
- ret = imx_hdmi_register(hdmi);
+ ret = imx_hdmi_register(drm, hdmi);
if (ret)
goto err_iahb;
- imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
+ /* Unmute interrupts */
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
- platform_set_drvdata(pdev, hdmi);
+ dev_set_drvdata(dev, hdmi);
return 0;
@@ -1881,20 +1718,35 @@ err_isfr:
return ret;
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
- struct drm_connector *connector = &hdmi->connector;
- struct drm_encoder *encoder = &hdmi->encoder;
+ struct imx_hdmi *hdmi = dev_get_drvdata(dev);
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(hdmi->imx_drm_connector);
- imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+ /* Disable all interrupts */
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder.funcs->destroy(&hdmi->encoder);
clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
i2c_put_adapter(hdmi->ddc);
+}
+
+static const struct component_ops hdmi_ops = {
+ .bind = imx_hdmi_bind,
+ .unbind = imx_hdmi_unbind,
+};
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &hdmi_ops);
+}
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &hdmi_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 7e593296ac4..7e3f019d7e7 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/clk.h>
+#include <linux/component.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
@@ -58,9 +59,8 @@ struct imx_ldb;
struct imx_ldb_channel {
struct imx_ldb *ldb;
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
+ struct device_node *child;
int chno;
void *edid;
int edid_len;
@@ -91,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect(
return connector_status_connected;
}
-static void imx_ldb_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_ldb_connector_get_modes(struct drm_connector *connector)
{
struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
@@ -111,6 +106,8 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode;
mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
drm_mode_copy(mode, &imx_ldb_ch->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
@@ -120,12 +117,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
-static int imx_ldb_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return 0;
-}
-
static struct drm_encoder *imx_ldb_connector_best_encoder(
struct drm_connector *connector)
{
@@ -168,7 +159,9 @@ static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
/* set display clock mux to LDB input clock */
ret = clk_set_parent(ldb->clk_sel[mux], ldb->clk[chno]);
if (ret)
- dev_err(ldb->dev, "unable to set di%d parent clock to ldb_di%d\n", mux, chno);
+ dev_err(ldb->dev,
+ "unable to set di%d parent clock to ldb_di%d\n", mux,
+ chno);
}
static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
@@ -179,8 +172,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
u32 pixel_fmt;
unsigned long serial_clk;
unsigned long di_clk = mode->clock * 1000;
- int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
/* dual channel LVDS mode */
@@ -189,7 +181,8 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
} else {
serial_clk = 7000UL * mode->clock;
- imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, di_clk);
+ imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
+ di_clk);
}
switch (imx_ldb_ch->chno) {
@@ -207,8 +200,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
pixel_fmt = V4L2_PIX_FMT_RGB24;
}
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS,
- pixel_fmt);
+ imx_drm_panel_format(encoder, pixel_fmt);
}
static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
@@ -216,8 +208,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
- int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
- encoder->crtc);
+ int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
if (dual) {
clk_prepare_enable(ldb->clk[0]);
@@ -316,26 +307,20 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
}
}
-static void imx_ldb_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_ldb_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_ldb_connector_detect,
- .destroy = imx_ldb_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
.get_modes = imx_ldb_connector_get_modes,
.best_encoder = imx_ldb_connector_best_encoder,
- .mode_valid = imx_ldb_connector_mode_valid,
};
static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
- .destroy = imx_ldb_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
@@ -351,56 +336,47 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
{
char clkname[16];
- sprintf(clkname, "di%d", chno);
+ snprintf(clkname, sizeof(clkname), "di%d", chno);
ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
if (IS_ERR(ldb->clk[chno]))
return PTR_ERR(ldb->clk[chno]);
- sprintf(clkname, "di%d_pll", chno);
+ snprintf(clkname, sizeof(clkname), "di%d_pll", chno);
ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname);
return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
}
-static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch)
+static int imx_ldb_register(struct drm_device *drm,
+ struct imx_ldb_channel *imx_ldb_ch)
{
- int ret;
struct imx_ldb *ldb = imx_ldb_ch->ldb;
+ int ret;
+
+ ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
+ imx_ldb_ch->child);
+ if (ret)
+ return ret;
ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
if (ret)
return ret;
+
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- ret |= imx_ldb_get_clk(ldb, 1);
+ ret = imx_ldb_get_clk(ldb, 1);
if (ret)
return ret;
}
- imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs;
- imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs;
-
- imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS;
- imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS;
-
drm_encoder_helper_add(&imx_ldb_ch->encoder,
&imx_ldb_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&imx_ldb_ch->encoder,
- &imx_ldb_ch->imx_drm_encoder, THIS_MODULE);
- if (ret) {
- dev_err(ldb->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
drm_connector_helper_add(&imx_ldb_ch->connector,
&imx_ldb_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&imx_ldb_ch->connector,
- &imx_ldb_ch->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder);
- dev_err(ldb->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &imx_ldb_ch->connector,
+ &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
&imx_ldb_ch->encoder);
@@ -459,11 +435,12 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
-static int imx_ldb_probe(struct platform_device *pdev)
+static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
const struct of_device_id *of_id =
- of_match_device(imx_ldb_dt_ids, &pdev->dev);
+ of_match_device(imx_ldb_dt_ids, dev);
struct device_node *child;
const u8 *edidp;
struct imx_ldb *imx_ldb;
@@ -473,17 +450,17 @@ static int imx_ldb_probe(struct platform_device *pdev)
int ret;
int i;
- imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
+ imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
if (!imx_ldb)
return -ENOMEM;
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(imx_ldb->regmap)) {
- dev_err(&pdev->dev, "failed to get parent regmap\n");
+ dev_err(dev, "failed to get parent regmap\n");
return PTR_ERR(imx_ldb->regmap);
}
- imx_ldb->dev = &pdev->dev;
+ imx_ldb->dev = dev;
if (of_id)
imx_ldb->lvds_mux = of_id->data;
@@ -521,7 +498,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
return -EINVAL;
if (dual && i > 0) {
- dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n");
+ dev_warn(dev, "dual-channel mode, ignoring second output\n");
continue;
}
@@ -531,6 +508,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
channel = &imx_ldb->channel[i];
channel->ldb = imx_ldb;
channel->chno = i;
+ channel->child = child;
edidp = of_get_property(child, "edid", &channel->edid_len);
if (edidp) {
@@ -553,54 +531,67 @@ static int imx_ldb_probe(struct platform_device *pdev)
case LVDS_BIT_MAP_SPWG:
if (datawidth == 24) {
if (i == 0 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
+ imx_ldb->ldb_ctrl |=
+ LDB_DATA_WIDTH_CH0_24;
if (i == 1 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
+ imx_ldb->ldb_ctrl |=
+ LDB_DATA_WIDTH_CH1_24;
}
break;
case LVDS_BIT_MAP_JEIDA:
if (datawidth == 18) {
- dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n");
+ dev_err(dev, "JEIDA standard only supported in 24 bit\n");
return -EINVAL;
}
if (i == 0 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | LDB_BIT_MAP_CH0_JEIDA;
+ imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+ LDB_BIT_MAP_CH0_JEIDA;
if (i == 1 || dual)
- imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA;
+ imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+ LDB_BIT_MAP_CH1_JEIDA;
break;
default:
- dev_err(&pdev->dev, "data mapping not specified or invalid\n");
+ dev_err(dev, "data mapping not specified or invalid\n");
return -EINVAL;
}
- ret = imx_ldb_register(channel);
+ ret = imx_ldb_register(drm, channel);
if (ret)
return ret;
-
- imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
}
- platform_set_drvdata(pdev, imx_ldb);
+ dev_set_drvdata(dev, imx_ldb);
return 0;
}
-static int imx_ldb_remove(struct platform_device *pdev)
+static void imx_ldb_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
+ struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
int i;
for (i = 0; i < 2; i++) {
struct imx_ldb_channel *channel = &imx_ldb->channel[i];
- struct drm_connector *connector = &channel->connector;
- struct drm_encoder *encoder = &channel->encoder;
-
- drm_mode_connector_detach_encoder(connector, encoder);
- imx_drm_remove_connector(channel->imx_drm_connector);
- imx_drm_remove_encoder(channel->imx_drm_encoder);
+ channel->connector.funcs->destroy(&channel->connector);
+ channel->encoder.funcs->destroy(&channel->encoder);
}
+}
+
+static const struct component_ops imx_ldb_ops = {
+ .bind = imx_ldb_bind,
+ .unbind = imx_ldb_unbind,
+};
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_ldb_ops);
+}
+
+static int imx_ldb_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_ldb_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 9abc7ca8b6c..c628fcdc22a 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -29,6 +30,7 @@
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
@@ -110,9 +112,7 @@ enum {
struct imx_tve {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
struct device *dev;
spinlock_t lock; /* register lock */
bool enabled;
@@ -225,11 +225,6 @@ static enum drm_connector_status imx_tve_connector_detect(
return connector_status_connected;
}
-static void imx_tve_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_tve_connector_get_modes(struct drm_connector *connector)
{
struct imx_tve *tve = con_to_tve(connector);
@@ -305,13 +300,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
switch (tve->mode) {
case TVE_MODE_VGA:
- imx_drm_crtc_panel_format_pins(encoder->crtc,
- DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24,
+ imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
tve->hsync_pin, tve->vsync_pin);
break;
case TVE_MODE_TVOUT:
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC,
- V4L2_PIX_FMT_YUV444);
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
break;
}
}
@@ -364,16 +357,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
tve_disable(tve);
}
-static void imx_tve_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_tve_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_tve_connector_detect,
- .destroy = imx_tve_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
@@ -383,7 +371,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
};
static struct drm_encoder_funcs imx_tve_encoder_funcs = {
- .destroy = imx_tve_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
@@ -503,34 +491,27 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
return 0;
}
-static int imx_tve_register(struct imx_tve *tve)
+static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
{
+ int encoder_type;
int ret;
- tve->connector.funcs = &imx_tve_connector_funcs;
- tve->encoder.funcs = &imx_tve_encoder_funcs;
+ encoder_type = tve->mode == TVE_MODE_VGA ?
+ DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
- tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
- tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+ ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
+ tve->dev->of_node);
+ if (ret)
+ return ret;
drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(tve->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
+ encoder_type);
drm_connector_helper_add(&tve->connector,
&imx_tve_connector_helper_funcs);
-
- ret = imx_drm_add_connector(&tve->connector,
- &tve->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(tve->imx_drm_encoder);
- dev_err(tve->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
@@ -576,9 +557,11 @@ static const int of_get_tve_mode(struct device_node *np)
return -EINVAL;
}
-static int imx_tve_probe(struct platform_device *pdev)
+static int imx_tve_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct imx_tve *tve;
struct resource *res;
@@ -587,14 +570,14 @@ static int imx_tve_probe(struct platform_device *pdev)
int irq;
int ret;
- tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+ tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
if (!tve)
return -ENOMEM;
- tve->dev = &pdev->dev;
+ tve->dev = dev;
spin_lock_init(&tve->lock);
- ddc_node = of_parse_phandle(np, "ddc", 0);
+ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
of_node_put(ddc_node);
@@ -602,7 +585,7 @@ static int imx_tve_probe(struct platform_device *pdev)
tve->mode = of_get_tve_mode(np);
if (tve->mode != TVE_MODE_VGA) {
- dev_err(&pdev->dev, "only VGA mode supported, currently\n");
+ dev_err(dev, "only VGA mode supported, currently\n");
return -EINVAL;
}
@@ -611,7 +594,7 @@ static int imx_tve_probe(struct platform_device *pdev)
&tve->hsync_pin);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get vsync pin\n");
+ dev_err(dev, "failed to get vsync pin\n");
return ret;
}
@@ -619,40 +602,40 @@ static int imx_tve_probe(struct platform_device *pdev)
&tve->vsync_pin);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get vsync pin\n");
+ dev_err(dev, "failed to get vsync pin\n");
return ret;
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
tve_regmap_config.lock_arg = tve;
- tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base,
+ tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
&tve_regmap_config);
if (IS_ERR(tve->regmap)) {
- dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ dev_err(dev, "failed to init regmap: %ld\n",
PTR_ERR(tve->regmap));
return PTR_ERR(tve->regmap);
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq\n");
+ dev_err(dev, "failed to get irq\n");
return irq;
}
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ret = devm_request_threaded_irq(dev, irq, NULL,
imx_tve_irq_handler, IRQF_ONESHOT,
"imx-tve", tve);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ dev_err(dev, "failed to request irq: %d\n", ret);
return ret;
}
- tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
+ tve->dac_reg = devm_regulator_get(dev, "dac");
if (!IS_ERR(tve->dac_reg)) {
regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
ret = regulator_enable(tve->dac_reg);
@@ -660,17 +643,17 @@ static int imx_tve_probe(struct platform_device *pdev)
return ret;
}
- tve->clk = devm_clk_get(&pdev->dev, "tve");
+ tve->clk = devm_clk_get(dev, "tve");
if (IS_ERR(tve->clk)) {
- dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n",
+ dev_err(dev, "failed to get high speed tve clock: %ld\n",
PTR_ERR(tve->clk));
return PTR_ERR(tve->clk);
}
/* this is the IPU DI clock input selector, can be parented to tve_di */
- tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel");
+ tve->di_sel_clk = devm_clk_get(dev, "di_sel");
if (IS_ERR(tve->di_sel_clk)) {
- dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n",
+ dev_err(dev, "failed to get ipu di mux clock: %ld\n",
PTR_ERR(tve->di_sel_clk));
return PTR_ERR(tve->di_sel_clk);
}
@@ -681,42 +664,51 @@ static int imx_tve_probe(struct platform_device *pdev)
ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret);
+ dev_err(dev, "failed to read configuration register: %d\n", ret);
return ret;
}
if (val != 0x00100000) {
- dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n");
+ dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
return -ENODEV;
}
/* disable cable detection for VGA mode */
ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
- ret = imx_tve_register(tve);
+ ret = imx_tve_register(drm, tve);
if (ret)
return ret;
- ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
-
- platform_set_drvdata(pdev, tve);
+ dev_set_drvdata(dev, tve);
return 0;
}
-static int imx_tve_remove(struct platform_device *pdev)
+static void imx_tve_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_tve *tve = platform_get_drvdata(pdev);
- struct drm_connector *connector = &tve->connector;
- struct drm_encoder *encoder = &tve->encoder;
-
- drm_mode_connector_detach_encoder(connector, encoder);
+ struct imx_tve *tve = dev_get_drvdata(dev);
- imx_drm_remove_connector(tve->imx_drm_connector);
- imx_drm_remove_encoder(tve->imx_drm_encoder);
+ tve->connector.funcs->destroy(&tve->connector);
+ tve->encoder.funcs->destroy(&tve->encoder);
if (!IS_ERR(tve->dac_reg))
regulator_disable(tve->dac_reg);
+}
+
+static const struct component_ops imx_tve_ops = {
+ .bind = imx_tve_bind,
+ .unbind = imx_tve_unbind,
+};
+static int imx_tve_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_tve_ops);
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_tve_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile
deleted file mode 100644
index 28ed72e98a9..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
-
-imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
deleted file mode 100644
index 4826b5c0249..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU Lesser General
- * Public License. You may obtain a copy of the GNU Lesser General
- * Public License Version 2.1 or later at the following locations:
- *
- * http://www.opensource.org/licenses/lgpl-license.html
- * http://www.gnu.org/copyleft/lgpl.html
- */
-
-#ifndef __DRM_IPU_H__
-#define __DRM_IPU_H__
-
-#include <linux/types.h>
-#include <linux/videodev2.h>
-#include <linux/bitmap.h>
-#include <linux/fb.h>
-
-struct ipu_soc;
-
-enum ipuv3_type {
- IPUV3EX,
- IPUV3M,
- IPUV3H,
-};
-
-/*
- * Bitfield of Display Interface signal polarities.
- */
-struct ipu_di_signal_cfg {
- unsigned datamask_en:1;
- unsigned interlaced:1;
- unsigned odd_field_first:1;
- unsigned clksel_en:1;
- unsigned clkidle_en:1;
- unsigned data_pol:1; /* true = inverted */
- unsigned clk_pol:1; /* true = rising edge */
- unsigned enable_pol:1;
- unsigned Hsync_pol:1; /* true = active high */
- unsigned Vsync_pol:1;
-
- u16 width;
- u16 height;
- u32 pixel_fmt;
- u16 h_start_width;
- u16 h_sync_width;
- u16 h_end_width;
- u16 v_start_width;
- u16 v_sync_width;
- u16 v_end_width;
- u32 v_to_h_sync;
- unsigned long pixelclock;
-#define IPU_DI_CLKMODE_SYNC (1 << 0)
-#define IPU_DI_CLKMODE_EXT (1 << 1)
- unsigned long clkflags;
-
- u8 hsync_pin;
- u8 vsync_pin;
-};
-
-enum ipu_color_space {
- IPUV3_COLORSPACE_RGB,
- IPUV3_COLORSPACE_YUV,
- IPUV3_COLORSPACE_UNKNOWN,
-};
-
-struct ipuv3_channel;
-
-enum ipu_channel_irq {
- IPU_IRQ_EOF = 0,
- IPU_IRQ_NFACK = 64,
- IPU_IRQ_NFB4EOF = 128,
- IPU_IRQ_EOS = 192,
-};
-
-int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
- enum ipu_channel_irq irq);
-
-#define IPU_IRQ_DP_SF_START (448 + 2)
-#define IPU_IRQ_DP_SF_END (448 + 3)
-#define IPU_IRQ_BG_SF_END IPU_IRQ_DP_SF_END,
-#define IPU_IRQ_DC_FC_0 (448 + 8)
-#define IPU_IRQ_DC_FC_1 (448 + 9)
-#define IPU_IRQ_DC_FC_2 (448 + 10)
-#define IPU_IRQ_DC_FC_3 (448 + 11)
-#define IPU_IRQ_DC_FC_4 (448 + 12)
-#define IPU_IRQ_DC_FC_6 (448 + 13)
-#define IPU_IRQ_VSYNC_PRE_0 (448 + 14)
-#define IPU_IRQ_VSYNC_PRE_1 (448 + 15)
-
-/*
- * IPU Image DMA Controller (idmac) functions
- */
-struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
-void ipu_idmac_put(struct ipuv3_channel *);
-
-int ipu_idmac_enable_channel(struct ipuv3_channel *channel);
-int ipu_idmac_disable_channel(struct ipuv3_channel *channel);
-int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
-
-void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
- bool doublebuffer);
-void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
-
-/*
- * IPU Display Controller (dc) functions
- */
-struct ipu_dc;
-struct ipu_di;
-struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);
-void ipu_dc_put(struct ipu_dc *dc);
-int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
- u32 pixel_fmt, u32 width);
-void ipu_dc_enable_channel(struct ipu_dc *dc);
-void ipu_dc_disable_channel(struct ipu_dc *dc);
-
-/*
- * IPU Display Interface (di) functions
- */
-struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp);
-void ipu_di_put(struct ipu_di *);
-int ipu_di_disable(struct ipu_di *);
-int ipu_di_enable(struct ipu_di *);
-int ipu_di_get_num(struct ipu_di *);
-int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig);
-
-/*
- * IPU Display Multi FIFO Controller (dmfc) functions
- */
-struct dmfc_channel;
-int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
-void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
-int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
- unsigned long bandwidth_mbs, int burstsize);
-void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
-int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
-struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipuv3_channel);
-void ipu_dmfc_put(struct dmfc_channel *dmfc);
-
-/*
- * IPU Display Processor (dp) functions
- */
-#define IPU_DP_FLOW_SYNC_BG 0
-#define IPU_DP_FLOW_SYNC_FG 1
-#define IPU_DP_FLOW_ASYNC0_BG 2
-#define IPU_DP_FLOW_ASYNC0_FG 3
-#define IPU_DP_FLOW_ASYNC1_BG 4
-#define IPU_DP_FLOW_ASYNC1_FG 5
-
-struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
-void ipu_dp_put(struct ipu_dp *);
-int ipu_dp_enable_channel(struct ipu_dp *dp);
-void ipu_dp_disable_channel(struct ipu_dp *dp);
-int ipu_dp_setup_channel(struct ipu_dp *dp,
- enum ipu_color_space in, enum ipu_color_space out);
-int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
-int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
- bool bg_chan);
-
-#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
-
-#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22)
-#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22)
-#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4)
-#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1)
-#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1)
-#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14)
-#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14)
-
-#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10)
-#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9)
-#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13)
-#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12)
-#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1)
-#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1)
-#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12)
-#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11)
-#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10)
-#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7)
-#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10)
-#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1)
-#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1)
-#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7)
-#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1)
-#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1)
-#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3)
-#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2)
-#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1)
-#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3)
-#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2)
-#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1)
-#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1)
-#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1)
-#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1)
-#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1)
-#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1)
-#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13)
-#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12)
-#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29)
-#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29)
-#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20)
-#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7)
-#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4)
-#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1)
-#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3)
-#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2)
-#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7)
-#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14)
-#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3)
-#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3)
-#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3)
-#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3)
-#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5)
-#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5)
-#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5)
-#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5)
-#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1)
-#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1)
-#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1)
-
-struct ipu_cpmem_word {
- u32 data[5];
- u32 res[3];
-};
-
-struct ipu_ch_param {
- struct ipu_cpmem_word word[2];
-};
-
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v);
-u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
-struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
-void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
-
-static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p)
-{
- int i;
- void __iomem *base = p;
-
- for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
- writel(0, base + i * sizeof(u32));
-}
-
-static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p,
- int bufnum, dma_addr_t buf)
-{
- if (bufnum)
- ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3);
- else
- ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3);
-}
-
-static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p,
- int xres, int yres)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1);
-}
-
-static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p,
- int stride)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1);
-}
-
-void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel);
-
-struct ipu_rgb {
- struct fb_bitfield red;
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp;
- int bits_per_pixel;
-};
-
-struct ipu_image {
- struct v4l2_pix_format pix;
- struct v4l2_rect rect;
- dma_addr_t phys;
-};
-
-int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
- int width);
-
-int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *,
- const struct ipu_rgb *rgb);
-
-static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
- int stride)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_SO, 1);
- ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8);
- ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1);
-};
-
-void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
- int stride, int height);
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
- u32 pixel_format);
-void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
- u32 pixel_format, int stride, int u_offset, int v_offset);
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
-int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
- struct ipu_image *image);
-
-enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
-enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
-
-static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
- int burstsize)
-{
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1);
-};
-
-struct ipu_client_platformdata {
- int di;
- int dc;
- int dp;
- int dmfc;
- int dma[2];
-};
-
-#endif /* __DRM_IPU_H__ */
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
deleted file mode 100644
index ca85d3d70ae..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ /dev/null
@@ -1,1261 +0,0 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-#include <linux/module.h>
-#include <linux/export.h>
-#include <linux/types.h>
-#include <linux/reset.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/list.h>
-#include <linux/irq.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of_device.h>
-
-#include <drm/drm_fourcc.h>
-
-#include "imx-ipu-v3.h"
-#include "ipu-prv.h"
-
-static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
-{
- return readl(ipu->cm_reg + offset);
-}
-
-static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
-{
- writel(value, ipu->cm_reg + offset);
-}
-
-static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
-{
- return readl(ipu->idmac_reg + offset);
-}
-
-static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
- unsigned offset)
-{
- writel(value, ipu->idmac_reg + offset);
-}
-
-void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
-{
- u32 val;
-
- val = ipu_cm_read(ipu, IPU_SRM_PRI2);
- val |= 0x8;
- ipu_cm_write(ipu, val, IPU_SRM_PRI2);
-}
-EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
-
-struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
-
- return ipu->cpmem_base + channel->num;
-}
-EXPORT_SYMBOL_GPL(ipu_get_cpmem);
-
-void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
- struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel);
- u32 val;
-
- if (ipu->ipu_type == IPUV3EX)
- ipu_ch_param_write_field(p, IPU_FIELD_ID, 1);
-
- val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num));
- val |= 1 << (channel->num % 32);
- ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num));
-};
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
-
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v)
-{
- u32 bit = (wbs >> 8) % 160;
- u32 size = wbs & 0xff;
- u32 word = (wbs >> 8) / 160;
- u32 i = bit / 32;
- u32 ofs = bit % 32;
- u32 mask = (1 << size) - 1;
- u32 val;
-
- pr_debug("%s %d %d %d\n", __func__, word, bit , size);
-
- val = readl(&base->word[word].data[i]);
- val &= ~(mask << ofs);
- val |= v << ofs;
- writel(val, &base->word[word].data[i]);
-
- if ((bit + size - 1) / 32 > i) {
- val = readl(&base->word[word].data[i + 1]);
- val &= ~(mask >> (ofs ? (32 - ofs) : 0));
- val |= v >> (ofs ? (32 - ofs) : 0);
- writel(val, &base->word[word].data[i + 1]);
- }
-}
-EXPORT_SYMBOL_GPL(ipu_ch_param_write_field);
-
-u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
-{
- u32 bit = (wbs >> 8) % 160;
- u32 size = wbs & 0xff;
- u32 word = (wbs >> 8) / 160;
- u32 i = bit / 32;
- u32 ofs = bit % 32;
- u32 mask = (1 << size) - 1;
- u32 val = 0;
-
- pr_debug("%s %d %d %d\n", __func__, word, bit , size);
-
- val = (readl(&base->word[word].data[i]) >> ofs) & mask;
-
- if ((bit + size - 1) / 32 > i) {
- u32 tmp;
- tmp = readl(&base->word[word].data[i + 1]);
- tmp &= mask >> (ofs ? (32 - ofs) : 0);
- val |= tmp << (ofs ? (32 - ofs) : 0);
- }
-
- return val;
-}
-EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
-
-int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
- const struct ipu_rgb *rgb)
-{
- int bpp = 0, npb = 0, ro, go, bo, to;
-
- ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
- go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
- bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
- to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
-
- ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro);
- ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go);
- ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo);
-
- if (rgb->transp.length) {
- ipu_ch_param_write_field(p, IPU_FIELD_WID3,
- rgb->transp.length - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to);
- } else {
- ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7);
- ipu_ch_param_write_field(p, IPU_FIELD_OFS3,
- rgb->bits_per_pixel);
- }
-
- switch (rgb->bits_per_pixel) {
- case 32:
- bpp = 0;
- npb = 15;
- break;
- case 24:
- bpp = 1;
- npb = 19;
- break;
- case 16:
- bpp = 3;
- npb = 31;
- break;
- case 8:
- bpp = 5;
- npb = 63;
- break;
- default:
- return -EINVAL;
- }
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
-
-int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
- int width)
-{
- int bpp = 0, npb = 0;
-
- switch (width) {
- case 32:
- bpp = 0;
- npb = 15;
- break;
- case 24:
- bpp = 1;
- npb = 19;
- break;
- case 16:
- bpp = 3;
- npb = 31;
- break;
- case 8:
- bpp = 5;
- npb = 63;
- break;
- default:
- return -EINVAL;
- }
-
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
-
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
- u32 pixel_format)
-{
- switch (pixel_format) {
- case V4L2_PIX_FMT_UYVY:
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0xA); /* pix format */
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */
- break;
- case V4L2_PIX_FMT_YUYV:
- ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */
- ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8); /* pix format */
- ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */
- break;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
-
-void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
- u32 pixel_format, int stride, int u_offset, int v_offset)
-{
- switch (pixel_format) {
- case V4L2_PIX_FMT_YUV420:
- ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8);
- ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8);
- break;
- case V4L2_PIX_FMT_YVU420:
- ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
- ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8);
- ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8);
- break;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
-
-void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
- int stride, int height)
-{
- int u_offset, v_offset;
- int uv_stride = 0;
-
- switch (pixel_format) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- uv_stride = stride / 2;
- u_offset = stride * height;
- v_offset = u_offset + (uv_stride * height / 2);
- ipu_cpmem_set_yuv_planar_full(p, pixel_format, stride,
- u_offset, v_offset);
- break;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
-
-static const struct ipu_rgb def_rgb_32 = {
- .red = { .offset = 16, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 0, .length = 8, },
- .transp = { .offset = 24, .length = 8, },
- .bits_per_pixel = 32,
-};
-
-static const struct ipu_rgb def_bgr_32 = {
- .red = { .offset = 0, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 16, .length = 8, },
- .transp = { .offset = 24, .length = 8, },
- .bits_per_pixel = 32,
-};
-
-static const struct ipu_rgb def_rgb_24 = {
- .red = { .offset = 16, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 0, .length = 8, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 24,
-};
-
-static const struct ipu_rgb def_bgr_24 = {
- .red = { .offset = 0, .length = 8, },
- .green = { .offset = 8, .length = 8, },
- .blue = { .offset = 16, .length = 8, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 24,
-};
-
-static const struct ipu_rgb def_rgb_16 = {
- .red = { .offset = 11, .length = 5, },
- .green = { .offset = 5, .length = 6, },
- .blue = { .offset = 0, .length = 5, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 16,
-};
-
-static const struct ipu_rgb def_bgr_16 = {
- .red = { .offset = 0, .length = 5, },
- .green = { .offset = 5, .length = 6, },
- .blue = { .offset = 11, .length = 5, },
- .transp = { .offset = 0, .length = 0, },
- .bits_per_pixel = 16,
-};
-
-#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \
- (pix->width * (y) / 4) + (x) / 2)
-#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \
- (pix->width * pix->height / 4) + \
- (pix->width * (y) / 4) + (x) / 2)
-
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc)
-{
- switch (drm_fourcc) {
- case DRM_FORMAT_YUV420:
- case DRM_FORMAT_YVU420:
- /* pix format */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2);
- /* burst size */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
- break;
- case DRM_FORMAT_UYVY:
- /* bits/pixel */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
- /* pix format */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA);
- /* burst size */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
- break;
- case DRM_FORMAT_YUYV:
- /* bits/pixel */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
- /* pix format */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8);
- /* burst size */
- ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
- break;
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_XBGR8888:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
- break;
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_XRGB8888:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
- break;
- case DRM_FORMAT_BGR888:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
- break;
- case DRM_FORMAT_RGB888:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
- break;
- case DRM_FORMAT_RGB565:
- ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
- break;
- case DRM_FORMAT_BGR565:
- ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
-
-/*
- * The V4L2 spec defines packed RGB formats in memory byte order, which from
- * point of view of the IPU corresponds to little-endian words with the first
- * component in the least significant bits.
- * The DRM pixel formats and IPU internal representation are ordered the other
- * way around, with the first named component ordered at the most significant
- * bits. Further, V4L2 formats are not well defined:
- * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
- * We choose the interpretation which matches GStreamer behavior.
- */
-static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
-{
- switch (pixelformat) {
- case V4L2_PIX_FMT_RGB565:
- /*
- * Here we choose the 'corrected' interpretation of RGBP, a
- * little-endian 16-bit word with the red component at the most
- * significant bits:
- * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
- */
- return DRM_FORMAT_RGB565;
- case V4L2_PIX_FMT_BGR24:
- /* B G R <=> [24:0] R:G:B */
- return DRM_FORMAT_RGB888;
- case V4L2_PIX_FMT_RGB24:
- /* R G B <=> [24:0] B:G:R */
- return DRM_FORMAT_BGR888;
- case V4L2_PIX_FMT_BGR32:
- /* B G R A <=> [32:0] A:B:G:R */
- return DRM_FORMAT_XRGB8888;
- case V4L2_PIX_FMT_RGB32:
- /* R G B A <=> [32:0] A:B:G:R */
- return DRM_FORMAT_XBGR8888;
- case V4L2_PIX_FMT_UYVY:
- return DRM_FORMAT_UYVY;
- case V4L2_PIX_FMT_YUYV:
- return DRM_FORMAT_YUYV;
- case V4L2_PIX_FMT_YUV420:
- return DRM_FORMAT_YUV420;
- case V4L2_PIX_FMT_YVU420:
- return DRM_FORMAT_YVU420;
- }
-
- return -EINVAL;
-}
-
-enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
-{
- switch (drm_fourcc) {
- case DRM_FORMAT_RGB565:
- case DRM_FORMAT_BGR565:
- case DRM_FORMAT_RGB888:
- case DRM_FORMAT_BGR888:
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_RGBX8888:
- case DRM_FORMAT_BGRX8888:
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_RGBA8888:
- case DRM_FORMAT_BGRA8888:
- return IPUV3_COLORSPACE_RGB;
- case DRM_FORMAT_YUYV:
- case DRM_FORMAT_UYVY:
- case DRM_FORMAT_YUV420:
- case DRM_FORMAT_YVU420:
- return IPUV3_COLORSPACE_YUV;
- default:
- return IPUV3_COLORSPACE_UNKNOWN;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
-
-int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
- struct ipu_image *image)
-{
- struct v4l2_pix_format *pix = &image->pix;
- int y_offset, u_offset, v_offset;
-
- pr_debug("%s: resolution: %dx%d stride: %d\n",
- __func__, pix->width, pix->height,
- pix->bytesperline);
-
- ipu_cpmem_set_resolution(cpmem, image->rect.width,
- image->rect.height);
- ipu_cpmem_set_stride(cpmem, pix->bytesperline);
-
- ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
-
- switch (pix->pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
- u_offset = U_OFFSET(pix, image->rect.left,
- image->rect.top) - y_offset;
- v_offset = V_OFFSET(pix, image->rect.left,
- image->rect.top) - y_offset;
-
- ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat,
- pix->bytesperline, u_offset, v_offset);
- ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset);
- break;
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 2 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_BGR32:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 4 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB565:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 2 +
- image->rect.top * image->pix.bytesperline);
- break;
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- ipu_cpmem_set_buffer(cpmem, 0, image->phys +
- image->rect.left * 3 +
- image->rect.top * image->pix.bytesperline);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
-
-enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
-{
- switch (pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- return IPUV3_COLORSPACE_YUV;
- case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_BGR32:
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_BGR24:
- case V4L2_PIX_FMT_RGB565:
- return IPUV3_COLORSPACE_RGB;
- default:
- return IPUV3_COLORSPACE_UNKNOWN;
- }
-}
-EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
-
-struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
-{
- struct ipuv3_channel *channel;
-
- dev_dbg(ipu->dev, "%s %d\n", __func__, num);
-
- if (num > 63)
- return ERR_PTR(-ENODEV);
-
- mutex_lock(&ipu->channel_lock);
-
- channel = &ipu->channel[num];
-
- if (channel->busy) {
- channel = ERR_PTR(-EBUSY);
- goto out;
- }
-
- channel->busy = true;
- channel->num = num;
-
-out:
- mutex_unlock(&ipu->channel_lock);
-
- return channel;
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_get);
-
-void ipu_idmac_put(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
-
- dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num);
-
- mutex_lock(&ipu->channel_lock);
-
- channel->busy = false;
-
- mutex_unlock(&ipu->channel_lock);
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_put);
-
-#define idma_mask(ch) (1 << (ch & 0x1f))
-
-void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
- bool doublebuffer)
-{
- struct ipu_soc *ipu = channel->ipu;
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&ipu->lock, flags);
-
- reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
- if (doublebuffer)
- reg |= idma_mask(channel->num);
- else
- reg &= ~idma_mask(channel->num);
- ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
-
- spin_unlock_irqrestore(&ipu->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
-
-int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
-{
- unsigned long lock_flags;
- u32 val;
-
- spin_lock_irqsave(&ipu->lock, lock_flags);
-
- val = ipu_cm_read(ipu, IPU_DISP_GEN);
-
- if (mask & IPU_CONF_DI0_EN)
- val |= IPU_DI0_COUNTER_RELEASE;
- if (mask & IPU_CONF_DI1_EN)
- val |= IPU_DI1_COUNTER_RELEASE;
-
- ipu_cm_write(ipu, val, IPU_DISP_GEN);
-
- val = ipu_cm_read(ipu, IPU_CONF);
- val |= mask;
- ipu_cm_write(ipu, val, IPU_CONF);
-
- spin_unlock_irqrestore(&ipu->lock, lock_flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_module_enable);
-
-int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
-{
- unsigned long lock_flags;
- u32 val;
-
- spin_lock_irqsave(&ipu->lock, lock_flags);
-
- val = ipu_cm_read(ipu, IPU_CONF);
- val &= ~mask;
- ipu_cm_write(ipu, val, IPU_CONF);
-
- val = ipu_cm_read(ipu, IPU_DISP_GEN);
-
- if (mask & IPU_CONF_DI0_EN)
- val &= ~IPU_DI0_COUNTER_RELEASE;
- if (mask & IPU_CONF_DI1_EN)
- val &= ~IPU_DI1_COUNTER_RELEASE;
-
- ipu_cm_write(ipu, val, IPU_DISP_GEN);
-
- spin_unlock_irqrestore(&ipu->lock, lock_flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_module_disable);
-
-void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
-{
- struct ipu_soc *ipu = channel->ipu;
- unsigned int chno = channel->num;
- unsigned long flags;
-
- spin_lock_irqsave(&ipu->lock, flags);
-
- /* Mark buffer as ready. */
- if (buf_num == 0)
- ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
- else
- ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
-
- spin_unlock_irqrestore(&ipu->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
-
-int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&ipu->lock, flags);
-
- val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
- val |= idma_mask(channel->num);
- ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
-
- spin_unlock_irqrestore(&ipu->lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
-
-int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
-{
- struct ipu_soc *ipu = channel->ipu;
- unsigned long timeout;
-
- timeout = jiffies + msecs_to_jiffies(ms);
- while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) &
- idma_mask(channel->num)) {
- if (time_after(jiffies, timeout))
- return -ETIMEDOUT;
- cpu_relax();
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
-
-int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
-{
- struct ipu_soc *ipu = channel->ipu;
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&ipu->lock, flags);
-
- /* Disable DMA channel(s) */
- val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
- val &= ~idma_mask(channel->num);
- ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
-
- /* Set channel buffers NOT to be ready */
- ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
-
- if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) &
- idma_mask(channel->num)) {
- ipu_cm_write(ipu, idma_mask(channel->num),
- IPU_CHA_BUF0_RDY(channel->num));
- }
-
- if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) &
- idma_mask(channel->num)) {
- ipu_cm_write(ipu, idma_mask(channel->num),
- IPU_CHA_BUF1_RDY(channel->num));
- }
-
- ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
-
- /* Reset the double buffer */
- val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
- val &= ~idma_mask(channel->num);
- ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
-
- spin_unlock_irqrestore(&ipu->lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
-
-static int ipu_memory_reset(struct ipu_soc *ipu)
-{
- unsigned long timeout;
-
- ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
-
- timeout = jiffies + msecs_to_jiffies(1000);
- while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
- if (time_after(jiffies, timeout))
- return -ETIME;
- cpu_relax();
- }
-
- return 0;
-}
-
-struct ipu_devtype {
- const char *name;
- unsigned long cm_ofs;
- unsigned long cpmem_ofs;
- unsigned long srm_ofs;
- unsigned long tpm_ofs;
- unsigned long disp0_ofs;
- unsigned long disp1_ofs;
- unsigned long dc_tmpl_ofs;
- unsigned long vdi_ofs;
- enum ipuv3_type type;
-};
-
-static struct ipu_devtype ipu_type_imx51 = {
- .name = "IPUv3EX",
- .cm_ofs = 0x1e000000,
- .cpmem_ofs = 0x1f000000,
- .srm_ofs = 0x1f040000,
- .tpm_ofs = 0x1f060000,
- .disp0_ofs = 0x1e040000,
- .disp1_ofs = 0x1e048000,
- .dc_tmpl_ofs = 0x1f080000,
- .vdi_ofs = 0x1e068000,
- .type = IPUV3EX,
-};
-
-static struct ipu_devtype ipu_type_imx53 = {
- .name = "IPUv3M",
- .cm_ofs = 0x06000000,
- .cpmem_ofs = 0x07000000,
- .srm_ofs = 0x07040000,
- .tpm_ofs = 0x07060000,
- .disp0_ofs = 0x06040000,
- .disp1_ofs = 0x06048000,
- .dc_tmpl_ofs = 0x07080000,
- .vdi_ofs = 0x06068000,
- .type = IPUV3M,
-};
-
-static struct ipu_devtype ipu_type_imx6q = {
- .name = "IPUv3H",
- .cm_ofs = 0x00200000,
- .cpmem_ofs = 0x00300000,
- .srm_ofs = 0x00340000,
- .tpm_ofs = 0x00360000,
- .disp0_ofs = 0x00240000,
- .disp1_ofs = 0x00248000,
- .dc_tmpl_ofs = 0x00380000,
- .vdi_ofs = 0x00268000,
- .type = IPUV3H,
-};
-
-static const struct of_device_id imx_ipu_dt_ids[] = {
- { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
- { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
- { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
-
-static int ipu_submodules_init(struct ipu_soc *ipu,
- struct platform_device *pdev, unsigned long ipu_base,
- struct clk *ipu_clk)
-{
- char *unit;
- int ret;
- struct device *dev = &pdev->dev;
- const struct ipu_devtype *devtype = ipu->devtype;
-
- ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
- IPU_CONF_DI0_EN, ipu_clk);
- if (ret) {
- unit = "di0";
- goto err_di_0;
- }
-
- ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs,
- IPU_CONF_DI1_EN, ipu_clk);
- if (ret) {
- unit = "di1";
- goto err_di_1;
- }
-
- ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs +
- IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs);
- if (ret) {
- unit = "dc_template";
- goto err_dc;
- }
-
- ret = ipu_dmfc_init(ipu, dev, ipu_base +
- devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk);
- if (ret) {
- unit = "dmfc";
- goto err_dmfc;
- }
-
- ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs);
- if (ret) {
- unit = "dp";
- goto err_dp;
- }
-
- return 0;
-
-err_dp:
- ipu_dmfc_exit(ipu);
-err_dmfc:
- ipu_dc_exit(ipu);
-err_dc:
- ipu_di_exit(ipu, 1);
-err_di_1:
- ipu_di_exit(ipu, 0);
-err_di_0:
- dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
- return ret;
-}
-
-static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
-{
- unsigned long status;
- int i, bit, irq;
-
- for (i = 0; i < num_regs; i++) {
-
- status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i]));
- status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
-
- for_each_set_bit(bit, &status, 32) {
- irq = irq_linear_revmap(ipu->domain, regs[i] * 32 + bit);
- if (irq)
- generic_handle_irq(irq);
- }
- }
-}
-
-static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
- const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
- struct irq_chip *chip = irq_get_chip(irq);
-
- chained_irq_enter(chip, desc);
-
- ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
-
- chained_irq_exit(chip, desc);
-}
-
-static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
- const int int_reg[] = { 4, 5, 8, 9};
- struct irq_chip *chip = irq_get_chip(irq);
-
- chained_irq_enter(chip, desc);
-
- ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg));
-
- chained_irq_exit(chip, desc);
-}
-
-int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
- enum ipu_channel_irq irq_type)
-{
- int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num);
-
- if (!irq)
- irq = irq_create_mapping(ipu->domain, irq_type + channel->num);
-
- return irq;
-}
-EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
-
-static void ipu_submodules_exit(struct ipu_soc *ipu)
-{
- ipu_dp_exit(ipu);
- ipu_dmfc_exit(ipu);
- ipu_dc_exit(ipu);
- ipu_di_exit(ipu, 1);
- ipu_di_exit(ipu, 0);
-}
-
-static int platform_remove_devices_fn(struct device *dev, void *unused)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- platform_device_unregister(pdev);
-
- return 0;
-}
-
-static void platform_device_unregister_children(struct platform_device *pdev)
-{
- device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
-}
-
-struct ipu_platform_reg {
- struct ipu_client_platformdata pdata;
- const char *name;
-};
-
-static const struct ipu_platform_reg client_reg[] = {
- {
- .pdata = {
- .di = 0,
- .dc = 5,
- .dp = IPU_DP_FLOW_SYNC_BG,
- .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
- .dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
- },
- .name = "imx-ipuv3-crtc",
- }, {
- .pdata = {
- .di = 1,
- .dc = 1,
- .dp = -EINVAL,
- .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC,
- .dma[1] = -EINVAL,
- },
- .name = "imx-ipuv3-crtc",
- },
-};
-
-static DEFINE_MUTEX(ipu_client_id_mutex);
-static int ipu_client_id;
-
-static int ipu_add_client_devices(struct ipu_soc *ipu)
-{
- struct device *dev = ipu->dev;
- unsigned i;
- int id, ret;
-
- mutex_lock(&ipu_client_id_mutex);
- id = ipu_client_id;
- ipu_client_id += ARRAY_SIZE(client_reg);
- mutex_unlock(&ipu_client_id_mutex);
-
- for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
- const struct ipu_platform_reg *reg = &client_reg[i];
- struct platform_device *pdev;
-
- pdev = platform_device_register_data(dev, reg->name,
- id++, &reg->pdata, sizeof(reg->pdata));
-
- if (IS_ERR(pdev))
- goto err_register;
- }
-
- return 0;
-
-err_register:
- platform_device_unregister_children(to_platform_device(dev));
-
- return ret;
-}
-
-
-static int ipu_irq_init(struct ipu_soc *ipu)
-{
- struct irq_chip_generic *gc;
- struct irq_chip_type *ct;
- unsigned long unused[IPU_NUM_IRQS / 32] = {
- 0x400100d0, 0xffe000fd,
- 0x400100d0, 0xffe000fd,
- 0x400100d0, 0xffe000fd,
- 0x4077ffff, 0xffe7e1fd,
- 0x23fffffe, 0x8880fff0,
- 0xf98fe7d0, 0xfff81fff,
- 0x400100d0, 0xffe000fd,
- 0x00000000,
- };
- int ret, i;
-
- ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS,
- &irq_generic_chip_ops, ipu);
- if (!ipu->domain) {
- dev_err(ipu->dev, "failed to add irq domain\n");
- return -ENODEV;
- }
-
- ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
- handle_level_irq, 0, IRQF_VALID, 0);
- if (ret < 0) {
- dev_err(ipu->dev, "failed to alloc generic irq chips\n");
- irq_domain_remove(ipu->domain);
- return ret;
- }
-
- for (i = 0; i < IPU_NUM_IRQS; i += 32) {
- gc = irq_get_domain_generic_chip(ipu->domain, i);
- gc->reg_base = ipu->cm_reg;
- gc->unused = unused[i / 32];
- ct = gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack_set_bit;
- ct->chip.irq_mask = irq_gc_mask_clr_bit;
- ct->chip.irq_unmask = irq_gc_mask_set_bit;
- ct->regs.ack = IPU_INT_STAT(i / 32);
- ct->regs.mask = IPU_INT_CTRL(i / 32);
- }
-
- irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler);
- irq_set_handler_data(ipu->irq_sync, ipu);
- irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler);
- irq_set_handler_data(ipu->irq_err, ipu);
-
- return 0;
-}
-
-static void ipu_irq_exit(struct ipu_soc *ipu)
-{
- int i, irq;
-
- irq_set_chained_handler(ipu->irq_err, NULL);
- irq_set_handler_data(ipu->irq_err, NULL);
- irq_set_chained_handler(ipu->irq_sync, NULL);
- irq_set_handler_data(ipu->irq_sync, NULL);
-
- /* TODO: remove irq_domain_generic_chips */
-
- for (i = 0; i < IPU_NUM_IRQS; i++) {
- irq = irq_linear_revmap(ipu->domain, i);
- if (irq)
- irq_dispose_mapping(irq);
- }
-
- irq_domain_remove(ipu->domain);
-}
-
-static int ipu_probe(struct platform_device *pdev)
-{
- const struct of_device_id *of_id =
- of_match_device(imx_ipu_dt_ids, &pdev->dev);
- struct ipu_soc *ipu;
- struct resource *res;
- unsigned long ipu_base;
- int i, ret, irq_sync, irq_err;
- const struct ipu_devtype *devtype;
-
- devtype = of_id->data;
-
- irq_sync = platform_get_irq(pdev, 0);
- irq_err = platform_get_irq(pdev, 1);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- dev_dbg(&pdev->dev, "irq_sync: %d irq_err: %d\n",
- irq_sync, irq_err);
-
- if (!res || irq_sync < 0 || irq_err < 0)
- return -ENODEV;
-
- ipu_base = res->start;
-
- ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL);
- if (!ipu)
- return -ENODEV;
-
- for (i = 0; i < 64; i++)
- ipu->channel[i].ipu = ipu;
- ipu->devtype = devtype;
- ipu->ipu_type = devtype->type;
-
- spin_lock_init(&ipu->lock);
- mutex_init(&ipu->channel_lock);
-
- dev_dbg(&pdev->dev, "cm_reg: 0x%08lx\n",
- ipu_base + devtype->cm_ofs);
- dev_dbg(&pdev->dev, "idmac: 0x%08lx\n",
- ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
- dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n",
- ipu_base + devtype->cpmem_ofs);
- dev_dbg(&pdev->dev, "disp0: 0x%08lx\n",
- ipu_base + devtype->disp0_ofs);
- dev_dbg(&pdev->dev, "disp1: 0x%08lx\n",
- ipu_base + devtype->disp1_ofs);
- dev_dbg(&pdev->dev, "srm: 0x%08lx\n",
- ipu_base + devtype->srm_ofs);
- dev_dbg(&pdev->dev, "tpm: 0x%08lx\n",
- ipu_base + devtype->tpm_ofs);
- dev_dbg(&pdev->dev, "dc: 0x%08lx\n",
- ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS);
- dev_dbg(&pdev->dev, "ic: 0x%08lx\n",
- ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS);
- dev_dbg(&pdev->dev, "dmfc: 0x%08lx\n",
- ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS);
- dev_dbg(&pdev->dev, "vdi: 0x%08lx\n",
- ipu_base + devtype->vdi_ofs);
-
- ipu->cm_reg = devm_ioremap(&pdev->dev,
- ipu_base + devtype->cm_ofs, PAGE_SIZE);
- ipu->idmac_reg = devm_ioremap(&pdev->dev,
- ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
- PAGE_SIZE);
- ipu->cpmem_base = devm_ioremap(&pdev->dev,
- ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
-
- if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
- return -ENOMEM;
-
- ipu->clk = devm_clk_get(&pdev->dev, "bus");
- if (IS_ERR(ipu->clk)) {
- ret = PTR_ERR(ipu->clk);
- dev_err(&pdev->dev, "clk_get failed with %d", ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, ipu);
-
- ret = clk_prepare_enable(ipu->clk);
- if (ret) {
- dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
- return ret;
- }
-
- ipu->dev = &pdev->dev;
- ipu->irq_sync = irq_sync;
- ipu->irq_err = irq_err;
-
- ret = ipu_irq_init(ipu);
- if (ret)
- goto out_failed_irq;
-
- ret = device_reset(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to reset: %d\n", ret);
- goto out_failed_reset;
- }
- ret = ipu_memory_reset(ipu);
- if (ret)
- goto out_failed_reset;
-
- /* Set MCU_T to divide MCU access window into 2 */
- ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
- IPU_DISP_GEN);
-
- ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk);
- if (ret)
- goto failed_submodules_init;
-
- ret = ipu_add_client_devices(ipu);
- if (ret) {
- dev_err(&pdev->dev, "adding client devices failed with %d\n",
- ret);
- goto failed_add_clients;
- }
-
- dev_info(&pdev->dev, "%s probed\n", devtype->name);
-
- return 0;
-
-failed_add_clients:
- ipu_submodules_exit(ipu);
-failed_submodules_init:
-out_failed_reset:
- ipu_irq_exit(ipu);
-out_failed_irq:
- clk_disable_unprepare(ipu->clk);
- return ret;
-}
-
-static int ipu_remove(struct platform_device *pdev)
-{
- struct ipu_soc *ipu = platform_get_drvdata(pdev);
-
- platform_device_unregister_children(pdev);
- ipu_submodules_exit(ipu);
- ipu_irq_exit(ipu);
-
- clk_disable_unprepare(ipu->clk);
-
- return 0;
-}
-
-static struct platform_driver imx_ipu_driver = {
- .driver = {
- .name = "imx-ipuv3",
- .of_match_table = imx_ipu_dt_ids,
- },
- .probe = ipu_probe,
- .remove = ipu_remove,
-};
-
-module_platform_driver(imx_ipu_driver);
-
-MODULE_ALIAS("platform:imx-ipuv3");
-MODULE_DESCRIPTION("i.MX IPU v3 driver");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
deleted file mode 100644
index d0e3bc3c53e..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include "../imx-drm.h"
-#include "imx-ipu-v3.h"
-#include "ipu-prv.h"
-
-#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2)
-#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2)
-
-#define DC_EVT_NF 0
-#define DC_EVT_NL 1
-#define DC_EVT_EOF 2
-#define DC_EVT_NFIELD 3
-#define DC_EVT_EOL 4
-#define DC_EVT_EOFIELD 5
-#define DC_EVT_NEW_ADDR 6
-#define DC_EVT_NEW_CHAN 7
-#define DC_EVT_NEW_DATA 8
-
-#define DC_EVT_NEW_ADDR_W_0 0
-#define DC_EVT_NEW_ADDR_W_1 1
-#define DC_EVT_NEW_CHAN_W_0 2
-#define DC_EVT_NEW_CHAN_W_1 3
-#define DC_EVT_NEW_DATA_W_0 4
-#define DC_EVT_NEW_DATA_W_1 5
-#define DC_EVT_NEW_ADDR_R_0 6
-#define DC_EVT_NEW_ADDR_R_1 7
-#define DC_EVT_NEW_CHAN_R_0 8
-#define DC_EVT_NEW_CHAN_R_1 9
-#define DC_EVT_NEW_DATA_R_0 10
-#define DC_EVT_NEW_DATA_R_1 11
-
-#define DC_WR_CH_CONF 0x0
-#define DC_WR_CH_ADDR 0x4
-#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2)
-
-#define DC_GEN 0xd4
-#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4)
-#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4)
-#define DC_STAT 0x1c8
-
-#define WROD(lf) (0x18 | ((lf) << 1))
-#define WRG 0x01
-#define WCLK 0xc9
-
-#define SYNC_WAVE 0
-#define NULL_WAVE (-1)
-
-#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
-#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
-
-#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0)
-#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0)
-#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0)
-#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0)
-#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3)
-#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3)
-#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4)
-#define DC_WR_CH_CONF_FIELD_MODE (1 << 9)
-#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5)
-#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5)
-#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2)
-#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3)
-
-#define IPU_DC_NUM_CHANNELS 10
-
-struct ipu_dc_priv;
-
-enum ipu_dc_map {
- IPU_DC_MAP_RGB24,
- IPU_DC_MAP_RGB565,
- IPU_DC_MAP_GBR24, /* TVEv2 */
- IPU_DC_MAP_BGR666,
- IPU_DC_MAP_BGR24,
-};
-
-struct ipu_dc {
- /* The display interface number assigned to this dc channel */
- unsigned int di;
- void __iomem *base;
- struct ipu_dc_priv *priv;
- int chno;
- bool in_use;
-};
-
-struct ipu_dc_priv {
- void __iomem *dc_reg;
- void __iomem *dc_tmpl_reg;
- struct ipu_soc *ipu;
- struct device *dev;
- struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
- struct mutex mutex;
-};
-
-static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
-{
- u32 reg;
-
- reg = readl(dc->base + DC_RL_CH(event));
- reg &= ~(0xffff << (16 * (event & 0x1)));
- reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
- writel(reg, dc->base + DC_RL_CH(event));
-}
-
-static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
- int map, int wave, int glue, int sync, int stop)
-{
- struct ipu_dc_priv *priv = dc->priv;
- u32 reg1, reg2;
-
- if (opcode == WCLK) {
- reg1 = (operand << 20) & 0xfff00000;
- reg2 = operand >> 12 | opcode << 1 | stop << 9;
- } else if (opcode == WRG) {
- reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
- reg2 = operand >> 17 | opcode << 7 | stop << 9;
- } else {
- reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
- reg2 = operand >> 12 | opcode << 4 | stop << 9;
- }
- writel(reg1, priv->dc_tmpl_reg + word * 8);
- writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
-}
-
-static int ipu_pixfmt_to_map(u32 fmt)
-{
- switch (fmt) {
- case V4L2_PIX_FMT_RGB24:
- return IPU_DC_MAP_RGB24;
- case V4L2_PIX_FMT_RGB565:
- return IPU_DC_MAP_RGB565;
- case IPU_PIX_FMT_GBR24:
- return IPU_DC_MAP_GBR24;
- case V4L2_PIX_FMT_BGR666:
- return IPU_DC_MAP_BGR666;
- case V4L2_PIX_FMT_BGR24:
- return IPU_DC_MAP_BGR24;
- default:
- return -EINVAL;
- }
-}
-
-int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
- u32 pixel_fmt, u32 width)
-{
- struct ipu_dc_priv *priv = dc->priv;
- u32 reg = 0;
- int map;
-
- dc->di = ipu_di_get_num(di);
-
- map = ipu_pixfmt_to_map(pixel_fmt);
- if (map < 0) {
- dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
- return map;
- }
-
- if (interlaced) {
- dc_link_event(dc, DC_EVT_NL, 0, 3);
- dc_link_event(dc, DC_EVT_EOL, 0, 2);
- dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1);
-
- /* Init template microcode */
- dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
- } else {
- if (dc->di) {
- dc_link_event(dc, DC_EVT_NL, 2, 3);
- dc_link_event(dc, DC_EVT_EOL, 3, 2);
- dc_link_event(dc, DC_EVT_NEW_DATA, 1, 1);
- /* Init template microcode */
- dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
- dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
- dc_write_tmpl(dc, 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
- dc_write_tmpl(dc, 1, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
- } else {
- dc_link_event(dc, DC_EVT_NL, 5, 3);
- dc_link_event(dc, DC_EVT_EOL, 6, 2);
- dc_link_event(dc, DC_EVT_NEW_DATA, 8, 1);
- /* Init template microcode */
- dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
- dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
- dc_write_tmpl(dc, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1);
- dc_write_tmpl(dc, 8, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
- }
- }
- dc_link_event(dc, DC_EVT_NF, 0, 0);
- dc_link_event(dc, DC_EVT_NFIELD, 0, 0);
- dc_link_event(dc, DC_EVT_EOF, 0, 0);
- dc_link_event(dc, DC_EVT_EOFIELD, 0, 0);
- dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0);
- dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0);
-
- reg = readl(dc->base + DC_WR_CH_CONF);
- if (interlaced)
- reg |= DC_WR_CH_CONF_FIELD_MODE;
- else
- reg &= ~DC_WR_CH_CONF_FIELD_MODE;
- writel(reg, dc->base + DC_WR_CH_CONF);
-
- writel(0x0, dc->base + DC_WR_CH_ADDR);
- writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
-
- ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
-
-void ipu_dc_enable_channel(struct ipu_dc *dc)
-{
- int di;
- u32 reg;
-
- di = dc->di;
-
- reg = readl(dc->base + DC_WR_CH_CONF);
- reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL;
- writel(reg, dc->base + DC_WR_CH_CONF);
-}
-EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
-
-void ipu_dc_disable_channel(struct ipu_dc *dc)
-{
- struct ipu_dc_priv *priv = dc->priv;
- u32 val;
- int irq = 0, timeout = 50;
-
- if (dc->chno == 1)
- irq = IPU_IRQ_DC_FC_1;
- else if (dc->chno == 5)
- irq = IPU_IRQ_DP_SF_END;
- else
- return;
-
- /* should wait for the interrupt here */
- mdelay(50);
-
- if (dc->di == 0)
- val = 0x00000002;
- else
- val = 0x00000020;
-
- /* Wait for DC triple buffer to empty */
- while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
- msleep(2);
- timeout -= 2;
- if (timeout <= 0)
- break;
- }
-
- val = readl(dc->base + DC_WR_CH_CONF);
- val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
- writel(val, dc->base + DC_WR_CH_CONF);
-}
-EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
-
-static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
- int byte_num, int offset, int mask)
-{
- int ptr = map * 3 + byte_num;
- u32 reg;
-
- reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr));
- reg &= ~(0xffff << (16 * (ptr & 0x1)));
- reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
- writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr));
-
- reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
- reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
- reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
- writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map));
-}
-
-static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map)
-{
- u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map));
-
- writel(reg & ~(0xffff << (16 * (map & 0x1))),
- priv->dc_reg + DC_MAP_CONF_PTR(map));
-}
-
-struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel)
-{
- struct ipu_dc_priv *priv = ipu->dc_priv;
- struct ipu_dc *dc;
-
- if (channel >= IPU_DC_NUM_CHANNELS)
- return ERR_PTR(-ENODEV);
-
- dc = &priv->channels[channel];
-
- mutex_lock(&priv->mutex);
-
- if (dc->in_use) {
- mutex_unlock(&priv->mutex);
- return ERR_PTR(-EBUSY);
- }
-
- dc->in_use = true;
-
- mutex_unlock(&priv->mutex);
-
- return dc;
-}
-EXPORT_SYMBOL_GPL(ipu_dc_get);
-
-void ipu_dc_put(struct ipu_dc *dc)
-{
- struct ipu_dc_priv *priv = dc->priv;
-
- mutex_lock(&priv->mutex);
- dc->in_use = false;
- mutex_unlock(&priv->mutex);
-}
-EXPORT_SYMBOL_GPL(ipu_dc_put);
-
-int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
- unsigned long base, unsigned long template_base)
-{
- struct ipu_dc_priv *priv;
- static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
- 0x78, 0, 0x94, 0xb4};
- int i;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- mutex_init(&priv->mutex);
-
- priv->dev = dev;
- priv->ipu = ipu;
- priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE);
- priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE);
- if (!priv->dc_reg || !priv->dc_tmpl_reg)
- return -ENOMEM;
-
- for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) {
- priv->channels[i].chno = i;
- priv->channels[i].priv = priv;
- priv->channels[i].base = priv->dc_reg + channel_offsets[i];
- }
-
- writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
- DC_WR_CH_CONF_PROG_DI_ID,
- priv->channels[1].base + DC_WR_CH_CONF);
- writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0),
- priv->channels[5].base + DC_WR_CH_CONF);
-
- writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, priv->dc_reg + DC_GEN);
-
- ipu->dc_priv = priv;
-
- dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n",
- base, template_base);
-
- /* rgb24 */
- ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24);
- ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */
- ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */
-
- /* rgb565 */
- ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565);
- ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */
- ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
-
- /* gbr24 */
- ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
- ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
- ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
-
- /* bgr666 */
- ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
-
- /* bgr24 */
- ipu_dc_map_clear(priv, IPU_DC_MAP_BGR24);
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 2, 7, 0xff); /* red */
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
-
- return 0;
-}
-
-void ipu_dc_exit(struct ipu_soc *ipu)
-{
-}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
deleted file mode 100644
index 948a49b289e..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ /dev/null
@@ -1,793 +0,0 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
-
-#include "imx-ipu-v3.h"
-#include "ipu-prv.h"
-
-struct ipu_di {
- void __iomem *base;
- int id;
- u32 module;
- struct clk *clk_di; /* display input clock */
- struct clk *clk_ipu; /* IPU bus clock */
- struct clk *clk_di_pixel; /* resulting pixel clock */
- struct clk_hw clk_hw_out;
- char *clk_name;
- bool inuse;
- unsigned long clkflags;
- struct ipu_soc *ipu;
-};
-
-static DEFINE_MUTEX(di_mutex);
-
-struct di_sync_config {
- int run_count;
- int run_src;
- int offset_count;
- int offset_src;
- int repeat_count;
- int cnt_clr_src;
- int cnt_polarity_gen_en;
- int cnt_polarity_clr_src;
- int cnt_polarity_trigger_src;
- int cnt_up;
- int cnt_down;
-};
-
-enum di_pins {
- DI_PIN11 = 0,
- DI_PIN12 = 1,
- DI_PIN13 = 2,
- DI_PIN14 = 3,
- DI_PIN15 = 4,
- DI_PIN16 = 5,
- DI_PIN17 = 6,
- DI_PIN_CS = 7,
-
- DI_PIN_SER_CLK = 0,
- DI_PIN_SER_RS = 1,
-};
-
-enum di_sync_wave {
- DI_SYNC_NONE = 0,
- DI_SYNC_CLK = 1,
- DI_SYNC_INT_HSYNC = 2,
- DI_SYNC_HSYNC = 3,
- DI_SYNC_VSYNC = 4,
- DI_SYNC_DE = 6,
-};
-
-#define SYNC_WAVE 0
-
-#define DI_GENERAL 0x0000
-#define DI_BS_CLKGEN0 0x0004
-#define DI_BS_CLKGEN1 0x0008
-#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1))
-#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1))
-#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2))
-#define DI_SYNC_AS_GEN 0x0054
-#define DI_DW_GEN(gen) (0x0058 + 4 * (gen))
-#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set)))
-#define DI_SER_CONF 0x015c
-#define DI_SSC 0x0160
-#define DI_POL 0x0164
-#define DI_AW0 0x0168
-#define DI_AW1 0x016c
-#define DI_SCR_CONF 0x0170
-#define DI_STAT 0x0174
-
-#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19)
-#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16)
-#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3)
-#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0)
-
-#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29)
-#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25)
-#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12)
-#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9)
-#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16)
-#define DI_SW_GEN1_CNT_UP(x) (x)
-#define DI_SW_GEN1_AUTO_RELOAD (0x10000000)
-
-#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24
-#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16
-
-#define DI_GEN_POLARITY_1 (1 << 0)
-#define DI_GEN_POLARITY_2 (1 << 1)
-#define DI_GEN_POLARITY_3 (1 << 2)
-#define DI_GEN_POLARITY_4 (1 << 3)
-#define DI_GEN_POLARITY_5 (1 << 4)
-#define DI_GEN_POLARITY_6 (1 << 5)
-#define DI_GEN_POLARITY_7 (1 << 6)
-#define DI_GEN_POLARITY_8 (1 << 7)
-#define DI_GEN_POLARITY_DISP_CLK (1 << 17)
-#define DI_GEN_DI_CLK_EXT (1 << 20)
-#define DI_GEN_DI_VSYNC_EXT (1 << 21)
-
-#define DI_POL_DRDY_DATA_POLARITY (1 << 7)
-#define DI_POL_DRDY_POLARITY_15 (1 << 4)
-
-#define DI_VSYNC_SEL_OFFSET 13
-
-static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
-{
- return readl(di->base + offset);
-}
-
-static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
-{
- writel(value, di->base + offset);
-}
-
-static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
-{
- u64 tmp = inrate;
- int div;
-
- tmp *= 16;
-
- do_div(tmp, outrate);
-
- div = tmp;
-
- if (div < 0x10)
- div = 0x10;
-
-#ifdef WTF_IS_THIS
- /*
- * Freescale has this in their Kernel. It is neither clear what
- * it does nor why it does it
- */
- if (div & 0x10)
- div &= ~0x7;
- else {
- /* Round up divider if it gets us closer to desired pix clk */
- if ((div & 0xC) == 0xC) {
- div += 0x10;
- div &= ~0xF;
- }
- }
-#endif
- return div;
-}
-
-static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- unsigned long outrate;
- u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
-
- if (div < 0x10)
- div = 0x10;
-
- outrate = (parent_rate / div) * 16;
-
- return outrate;
-}
-
-static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- unsigned long outrate;
- int div;
- u32 val;
-
- div = ipu_di_clk_calc_div(*prate, rate);
-
- outrate = (*prate / div) * 16;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
- outrate = *prate / 2;
-
- dev_dbg(di->ipu->dev,
- "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
- __func__, *prate, div, outrate, rate);
-
- return outrate;
-}
-
-static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- int div;
- u32 clkgen0;
-
- clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
-
- div = ipu_di_clk_calc_div(parent_rate, rate);
-
- ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
-
- dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
- __func__, parent_rate, rate, div);
- return 0;
-}
-
-static u8 clk_di_get_parent(struct clk_hw *hw)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- u32 val;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
-}
-
-static int clk_di_set_parent(struct clk_hw *hw, u8 index)
-{
- struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
- u32 val;
-
- val = ipu_di_read(di, DI_GENERAL);
-
- if (index)
- val |= DI_GEN_DI_CLK_EXT;
- else
- val &= ~DI_GEN_DI_CLK_EXT;
-
- ipu_di_write(di, val, DI_GENERAL);
-
- return 0;
-}
-
-static struct clk_ops clk_di_ops = {
- .round_rate = clk_di_round_rate,
- .set_rate = clk_di_set_rate,
- .recalc_rate = clk_di_recalc_rate,
- .set_parent = clk_di_set_parent,
- .get_parent = clk_di_get_parent,
-};
-
-static void ipu_di_data_wave_config(struct ipu_di *di,
- int wave_gen,
- int access_size, int component_size)
-{
- u32 reg;
- reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
- (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
- ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
-}
-
-static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin,
- int set, int up, int down)
-{
- u32 reg;
-
- reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
- reg &= ~(0x3 << (di_pin * 2));
- reg |= set << (di_pin * 2);
- ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
-
- ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
-}
-
-static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
- int start, int count)
-{
- u32 reg;
- int i;
-
- for (i = 0; i < count; i++) {
- struct di_sync_config *c = &config[i];
- int wave_gen = start + i + 1;
-
- if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) ||
- (c->repeat_count >= 0x1000) ||
- (c->cnt_up >= 0x400) ||
- (c->cnt_down >= 0x400)) {
- dev_err(di->ipu->dev, "DI%d counters out of range.\n",
- di->id);
- return;
- }
-
- reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
- DI_SW_GEN0_RUN_SRC(c->run_src) |
- DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
- DI_SW_GEN0_OFFSET_SRC(c->offset_src);
- ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
-
- reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
- DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
- DI_SW_GEN1_CNT_POL_TRIGGER_SRC(
- c->cnt_polarity_trigger_src) |
- DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
- DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
- DI_SW_GEN1_CNT_UP(c->cnt_up);
-
- /* Enable auto reload */
- if (c->repeat_count == 0)
- reg |= DI_SW_GEN1_AUTO_RELOAD;
-
- ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
-
- reg = ipu_di_read(di, DI_STP_REP(wave_gen));
- reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
- reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
- ipu_di_write(di, reg, DI_STP_REP(wave_gen));
- }
-}
-
-static void ipu_di_sync_config_interlaced(struct ipu_di *di,
- struct ipu_di_signal_cfg *sig)
-{
- u32 h_total = sig->width + sig->h_sync_width +
- sig->h_start_width + sig->h_end_width;
- u32 v_total = sig->height + sig->v_sync_width +
- sig->v_start_width + sig->v_end_width;
- u32 reg;
- struct di_sync_config cfg[] = {
- {
- .run_count = h_total / 2 - 1,
- .run_src = DI_SYNC_CLK,
- }, {
- .run_count = h_total - 11,
- .run_src = DI_SYNC_CLK,
- .cnt_down = 4,
- }, {
- .run_count = v_total * 2 - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = 1,
- .offset_src = DI_SYNC_INT_HSYNC,
- .cnt_down = 4,
- }, {
- .run_count = v_total / 2 - 1,
- .run_src = DI_SYNC_HSYNC,
- .offset_count = sig->v_start_width,
- .offset_src = DI_SYNC_HSYNC,
- .repeat_count = 2,
- .cnt_clr_src = DI_SYNC_VSYNC,
- }, {
- .run_src = DI_SYNC_HSYNC,
- .repeat_count = sig->height / 2,
- .cnt_clr_src = 4,
- }, {
- .run_count = v_total - 1,
- .run_src = DI_SYNC_HSYNC,
- }, {
- .run_count = v_total / 2 - 1,
- .run_src = DI_SYNC_HSYNC,
- .offset_count = 9,
- .offset_src = DI_SYNC_HSYNC,
- .repeat_count = 2,
- .cnt_clr_src = DI_SYNC_VSYNC,
- }, {
- .run_src = DI_SYNC_CLK,
- .offset_count = sig->h_start_width,
- .offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
- .cnt_clr_src = 5,
- }, {
- .run_count = v_total - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = v_total / 2,
- .offset_src = DI_SYNC_INT_HSYNC,
- .cnt_clr_src = DI_SYNC_HSYNC,
- .cnt_down = 4,
- }
- };
-
- ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
-
- /* set gentime select and tag sel */
- reg = ipu_di_read(di, DI_SW_GEN1(9));
- reg &= 0x1FFFFFFF;
- reg |= (3 - 1) << 29 | 0x00008000;
- ipu_di_write(di, reg, DI_SW_GEN1(9));
-
- ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
-}
-
-static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
- struct ipu_di_signal_cfg *sig, int div)
-{
- u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
- sig->h_end_width;
- u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
- sig->v_end_width;
- struct di_sync_config cfg[] = {
- {
- /* 1: INT_HSYNC */
- .run_count = h_total - 1,
- .run_src = DI_SYNC_CLK,
- } , {
- /* PIN2: HSYNC */
- .run_count = h_total - 1,
- .run_src = DI_SYNC_CLK,
- .offset_count = div * sig->v_to_h_sync,
- .offset_src = DI_SYNC_CLK,
- .cnt_polarity_gen_en = 1,
- .cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
- } , {
- /* PIN3: VSYNC */
- .run_count = v_total - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .cnt_polarity_gen_en = 1,
- .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
- } , {
- /* 4: Line Active */
- .run_src = DI_SYNC_HSYNC,
- .offset_count = sig->v_sync_width + sig->v_start_width,
- .offset_src = DI_SYNC_HSYNC,
- .repeat_count = sig->height,
- .cnt_clr_src = DI_SYNC_VSYNC,
- } , {
- /* 5: Pixel Active, referenced by DC */
- .run_src = DI_SYNC_CLK,
- .offset_count = sig->h_sync_width + sig->h_start_width,
- .offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
- .cnt_clr_src = 5, /* Line Active */
- } , {
- /* unused */
- } , {
- /* unused */
- } , {
- /* unused */
- } , {
- /* unused */
- },
- };
- /* can't use #7 and #8 for line active and pixel active counters */
- struct di_sync_config cfg_vga[] = {
- {
- /* 1: INT_HSYNC */
- .run_count = h_total - 1,
- .run_src = DI_SYNC_CLK,
- } , {
- /* 2: VSYNC */
- .run_count = v_total - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- } , {
- /* 3: Line Active */
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = sig->v_sync_width + sig->v_start_width,
- .offset_src = DI_SYNC_INT_HSYNC,
- .repeat_count = sig->height,
- .cnt_clr_src = 3 /* VSYNC */,
- } , {
- /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
- .run_count = h_total - 1,
- .run_src = DI_SYNC_CLK,
- .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
- .offset_src = DI_SYNC_CLK,
- .cnt_polarity_gen_en = 1,
- .cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
- } , {
- /* 5: Pixel Active signal to DC */
- .run_src = DI_SYNC_CLK,
- .offset_count = sig->h_sync_width + sig->h_start_width,
- .offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
- .cnt_clr_src = 4, /* Line Active */
- } , {
- /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
- .run_count = v_total - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = 1, /* magic value from Freescale TVE driver */
- .offset_src = DI_SYNC_INT_HSYNC,
- .cnt_polarity_gen_en = 1,
- .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
- } , {
- /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
- .run_count = h_total - 1,
- .run_src = DI_SYNC_CLK,
- .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
- .offset_src = DI_SYNC_CLK,
- .cnt_polarity_gen_en = 1,
- .cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
- } , {
- /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
- .run_count = v_total - 1,
- .run_src = DI_SYNC_INT_HSYNC,
- .offset_count = 1, /* magic value from Freescale TVE driver */
- .offset_src = DI_SYNC_INT_HSYNC,
- .cnt_polarity_gen_en = 1,
- .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
- } , {
- /* unused */
- },
- };
-
- ipu_di_write(di, v_total - 1, DI_SCR_CONF);
- if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
- ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
- else
- ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
-}
-
-int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
-{
- u32 reg;
- u32 di_gen, vsync_cnt;
- u32 div;
- u32 h_total, v_total;
- int ret;
- unsigned long round;
- struct clk *parent;
-
- dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
- di->id, sig->width, sig->height);
-
- if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
- return -EINVAL;
-
- if (sig->clkflags & IPU_DI_CLKMODE_EXT)
- parent = di->clk_di;
- else
- parent = di->clk_ipu;
-
- ret = clk_set_parent(di->clk_di_pixel, parent);
- if (ret) {
- dev_err(di->ipu->dev,
- "setting pixel clock to parent %s failed with %d\n",
- __clk_get_name(parent), ret);
- return ret;
- }
-
- if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
- round = clk_get_rate(parent);
- else
- round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
-
- ret = clk_set_rate(di->clk_di_pixel, round);
-
- h_total = sig->width + sig->h_sync_width + sig->h_start_width +
- sig->h_end_width;
- v_total = sig->height + sig->v_sync_width + sig->v_start_width +
- sig->v_end_width;
-
- mutex_lock(&di_mutex);
-
- div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
- div = div / 16; /* Now divider is integer portion */
-
- /* Setup pixel clock timing */
- /* Down time is half of period */
- ipu_di_write(di, (div << 16), DI_BS_CLKGEN1);
-
- ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1);
- ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
-
- di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
- di_gen |= DI_GEN_DI_VSYNC_EXT;
-
- if (sig->interlaced) {
- ipu_di_sync_config_interlaced(di, sig);
-
- /* set y_sel = 1 */
- di_gen |= 0x10000000;
- di_gen |= DI_GEN_POLARITY_5;
- di_gen |= DI_GEN_POLARITY_8;
-
- vsync_cnt = 7;
-
- if (sig->Hsync_pol)
- di_gen |= DI_GEN_POLARITY_3;
- if (sig->Vsync_pol)
- di_gen |= DI_GEN_POLARITY_2;
- } else {
- ipu_di_sync_config_noninterlaced(di, sig, div);
-
- vsync_cnt = 3;
- if (di->id == 1)
- /*
- * TODO: change only for TVEv2, parallel display
- * uses pin 2 / 3
- */
- if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
- vsync_cnt = 6;
-
- if (sig->Hsync_pol) {
- if (sig->hsync_pin == 2)
- di_gen |= DI_GEN_POLARITY_2;
- else if (sig->hsync_pin == 4)
- di_gen |= DI_GEN_POLARITY_4;
- else if (sig->hsync_pin == 7)
- di_gen |= DI_GEN_POLARITY_7;
- }
- if (sig->Vsync_pol) {
- if (sig->vsync_pin == 3)
- di_gen |= DI_GEN_POLARITY_3;
- else if (sig->vsync_pin == 6)
- di_gen |= DI_GEN_POLARITY_6;
- else if (sig->vsync_pin == 8)
- di_gen |= DI_GEN_POLARITY_8;
- }
- }
-
- if (!sig->clk_pol)
- di_gen |= DI_GEN_POLARITY_DISP_CLK;
-
- ipu_di_write(di, di_gen, DI_GENERAL);
-
- ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
- DI_SYNC_AS_GEN);
-
- reg = ipu_di_read(di, DI_POL);
- reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
-
- if (sig->enable_pol)
- reg |= DI_POL_DRDY_POLARITY_15;
- if (sig->data_pol)
- reg |= DI_POL_DRDY_DATA_POLARITY;
-
- ipu_di_write(di, reg, DI_POL);
-
- mutex_unlock(&di_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
-
-int ipu_di_enable(struct ipu_di *di)
-{
- int ret = clk_prepare_enable(di->clk_di_pixel);
- if (ret)
- return ret;
-
- ipu_module_enable(di->ipu, di->module);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_di_enable);
-
-int ipu_di_disable(struct ipu_di *di)
-{
- ipu_module_disable(di->ipu, di->module);
-
- clk_disable_unprepare(di->clk_di_pixel);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_di_disable);
-
-int ipu_di_get_num(struct ipu_di *di)
-{
- return di->id;
-}
-EXPORT_SYMBOL_GPL(ipu_di_get_num);
-
-static DEFINE_MUTEX(ipu_di_lock);
-
-struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
-{
- struct ipu_di *di;
-
- if (disp > 1)
- return ERR_PTR(-EINVAL);
-
- di = ipu->di_priv[disp];
-
- mutex_lock(&ipu_di_lock);
-
- if (di->inuse) {
- di = ERR_PTR(-EBUSY);
- goto out;
- }
-
- di->inuse = true;
-out:
- mutex_unlock(&ipu_di_lock);
-
- return di;
-}
-EXPORT_SYMBOL_GPL(ipu_di_get);
-
-void ipu_di_put(struct ipu_di *di)
-{
- mutex_lock(&ipu_di_lock);
-
- di->inuse = false;
-
- mutex_unlock(&ipu_di_lock);
-}
-EXPORT_SYMBOL_GPL(ipu_di_put);
-
-int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
- unsigned long base,
- u32 module, struct clk *clk_ipu)
-{
- struct ipu_di *di;
- int ret;
- const char *di_parent[2];
- struct clk_init_data init = {
- .ops = &clk_di_ops,
- .num_parents = 2,
- .flags = 0,
- };
-
- if (id > 1)
- return -ENODEV;
-
- di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
- if (!di)
- return -ENOMEM;
-
- ipu->di_priv[id] = di;
-
- di->clk_di = devm_clk_get(dev, id ? "di1" : "di0");
- if (IS_ERR(di->clk_di))
- return PTR_ERR(di->clk_di);
-
- di->module = module;
- di->id = id;
- di->clk_ipu = clk_ipu;
- di->base = devm_ioremap(dev, base, PAGE_SIZE);
- if (!di->base)
- return -ENOMEM;
-
- di_parent[0] = __clk_get_name(di->clk_ipu);
- di_parent[1] = __clk_get_name(di->clk_di);
-
- ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
-
- init.parent_names = (const char **)&di_parent;
- di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
- dev_name(dev), id);
- if (!di->clk_name)
- return -ENOMEM;
-
- init.name = di->clk_name;
-
- di->clk_hw_out.init = &init;
- di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
-
- if (IS_ERR(di->clk_di_pixel)) {
- ret = PTR_ERR(di->clk_di_pixel);
- goto failed_clk_register;
- }
-
- dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
- id, base, di->base);
- di->inuse = false;
- di->ipu = ipu;
-
- return 0;
-
-failed_clk_register:
-
- kfree(di->clk_name);
-
- return ret;
-}
-
-void ipu_di_exit(struct ipu_soc *ipu, int id)
-{
- struct ipu_di *di = ipu->di_priv[id];
-
- clk_unregister(di->clk_di_pixel);
- kfree(di->clk_name);
-}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
deleted file mode 100644
index 98070dd8c92..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-#include <linux/export.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-
-#include "imx-ipu-v3.h"
-#include "ipu-prv.h"
-
-#define DMFC_RD_CHAN 0x0000
-#define DMFC_WR_CHAN 0x0004
-#define DMFC_WR_CHAN_DEF 0x0008
-#define DMFC_DP_CHAN 0x000c
-#define DMFC_DP_CHAN_DEF 0x0010
-#define DMFC_GENERAL1 0x0014
-#define DMFC_GENERAL2 0x0018
-#define DMFC_IC_CTRL 0x001c
-#define DMFC_STAT 0x0020
-
-#define DMFC_WR_CHAN_1_28 0
-#define DMFC_WR_CHAN_2_41 8
-#define DMFC_WR_CHAN_1C_42 16
-#define DMFC_WR_CHAN_2C_43 24
-
-#define DMFC_DP_CHAN_5B_23 0
-#define DMFC_DP_CHAN_5F_27 8
-#define DMFC_DP_CHAN_6B_24 16
-#define DMFC_DP_CHAN_6F_29 24
-
-#define DMFC_FIFO_SIZE_64 (3 << 3)
-#define DMFC_FIFO_SIZE_128 (2 << 3)
-#define DMFC_FIFO_SIZE_256 (1 << 3)
-#define DMFC_FIFO_SIZE_512 (0 << 3)
-
-#define DMFC_SEGMENT(x) ((x & 0x7) << 0)
-#define DMFC_BURSTSIZE_128 (0 << 6)
-#define DMFC_BURSTSIZE_64 (1 << 6)
-#define DMFC_BURSTSIZE_32 (2 << 6)
-#define DMFC_BURSTSIZE_16 (3 << 6)
-
-struct dmfc_channel_data {
- int ipu_channel;
- unsigned long channel_reg;
- unsigned long shift;
- unsigned eot_shift;
- unsigned max_fifo_lines;
-};
-
-static const struct dmfc_channel_data dmfcdata[] = {
- {
- .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
- .channel_reg = DMFC_DP_CHAN,
- .shift = DMFC_DP_CHAN_5B_23,
- .eot_shift = 20,
- .max_fifo_lines = 3,
- }, {
- .ipu_channel = 24,
- .channel_reg = DMFC_DP_CHAN,
- .shift = DMFC_DP_CHAN_6B_24,
- .eot_shift = 22,
- .max_fifo_lines = 1,
- }, {
- .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
- .channel_reg = DMFC_DP_CHAN,
- .shift = DMFC_DP_CHAN_5F_27,
- .eot_shift = 21,
- .max_fifo_lines = 2,
- }, {
- .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
- .channel_reg = DMFC_WR_CHAN,
- .shift = DMFC_WR_CHAN_1_28,
- .eot_shift = 16,
- .max_fifo_lines = 2,
- }, {
- .ipu_channel = 29,
- .channel_reg = DMFC_DP_CHAN,
- .shift = DMFC_DP_CHAN_6F_29,
- .eot_shift = 23,
- .max_fifo_lines = 1,
- },
-};
-
-#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
-
-struct ipu_dmfc_priv;
-
-struct dmfc_channel {
- unsigned slots;
- unsigned slotmask;
- unsigned segment;
- int burstsize;
- struct ipu_soc *ipu;
- struct ipu_dmfc_priv *priv;
- const struct dmfc_channel_data *data;
-};
-
-struct ipu_dmfc_priv {
- struct ipu_soc *ipu;
- struct device *dev;
- struct dmfc_channel channels[DMFC_NUM_CHANNELS];
- struct mutex mutex;
- unsigned long bandwidth_per_slot;
- void __iomem *base;
- int use_count;
-};
-
-int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
-{
- struct ipu_dmfc_priv *priv = dmfc->priv;
- mutex_lock(&priv->mutex);
-
- if (!priv->use_count)
- ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
-
- priv->use_count++;
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
-
-void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
-{
- struct ipu_dmfc_priv *priv = dmfc->priv;
-
- mutex_lock(&priv->mutex);
-
- priv->use_count--;
-
- if (!priv->use_count)
- ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
-
- if (priv->use_count < 0)
- priv->use_count = 0;
-
- mutex_unlock(&priv->mutex);
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
-
-static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
- int segment, int burstsize)
-{
- struct ipu_dmfc_priv *priv = dmfc->priv;
- u32 val, field;
-
- dev_dbg(priv->dev,
- "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
- slots, segment, dmfc->data->ipu_channel);
-
- if (!dmfc)
- return -EINVAL;
-
- switch (slots) {
- case 1:
- field = DMFC_FIFO_SIZE_64;
- break;
- case 2:
- field = DMFC_FIFO_SIZE_128;
- break;
- case 4:
- field = DMFC_FIFO_SIZE_256;
- break;
- case 8:
- field = DMFC_FIFO_SIZE_512;
- break;
- default:
- return -EINVAL;
- }
-
- switch (burstsize) {
- case 16:
- field |= DMFC_BURSTSIZE_16;
- break;
- case 32:
- field |= DMFC_BURSTSIZE_32;
- break;
- case 64:
- field |= DMFC_BURSTSIZE_64;
- break;
- case 128:
- field |= DMFC_BURSTSIZE_128;
- break;
- }
-
- field |= DMFC_SEGMENT(segment);
-
- val = readl(priv->base + dmfc->data->channel_reg);
-
- val &= ~(0xff << dmfc->data->shift);
- val |= field << dmfc->data->shift;
-
- writel(val, priv->base + dmfc->data->channel_reg);
-
- dmfc->slots = slots;
- dmfc->segment = segment;
- dmfc->burstsize = burstsize;
- dmfc->slotmask = ((1 << slots) - 1) << segment;
-
- return 0;
-}
-
-static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
- unsigned long bandwidth)
-{
- int slots = 1;
-
- while (slots * priv->bandwidth_per_slot < bandwidth)
- slots *= 2;
-
- return slots;
-}
-
-static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
-{
- unsigned slotmask_need, slotmask_used = 0;
- int i, segment = 0;
-
- slotmask_need = (1 << slots) - 1;
-
- for (i = 0; i < DMFC_NUM_CHANNELS; i++)
- slotmask_used |= priv->channels[i].slotmask;
-
- while (slotmask_need <= 0xff) {
- if (!(slotmask_used & slotmask_need))
- return segment;
-
- slotmask_need <<= 1;
- segment++;
- }
-
- return -EBUSY;
-}
-
-void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
-{
- struct ipu_dmfc_priv *priv = dmfc->priv;
- int i;
-
- dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
- dmfc->slots, dmfc->segment);
-
- mutex_lock(&priv->mutex);
-
- if (!dmfc->slots)
- goto out;
-
- dmfc->slotmask = 0;
- dmfc->slots = 0;
- dmfc->segment = 0;
-
- for (i = 0; i < DMFC_NUM_CHANNELS; i++)
- priv->channels[i].slotmask = 0;
-
- for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
- if (priv->channels[i].slots > 0) {
- priv->channels[i].segment =
- dmfc_find_slots(priv, priv->channels[i].slots);
- priv->channels[i].slotmask =
- ((1 << priv->channels[i].slots) - 1) <<
- priv->channels[i].segment;
- }
- }
-
- for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
- if (priv->channels[i].slots > 0)
- ipu_dmfc_setup_channel(&priv->channels[i],
- priv->channels[i].slots,
- priv->channels[i].segment,
- priv->channels[i].burstsize);
- }
-out:
- mutex_unlock(&priv->mutex);
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
-
-int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
- unsigned long bandwidth_pixel_per_second, int burstsize)
-{
- struct ipu_dmfc_priv *priv = dmfc->priv;
- int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
- int segment = -1, ret = 0;
-
- dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
- bandwidth_pixel_per_second / 1000000,
- dmfc->data->ipu_channel);
-
- ipu_dmfc_free_bandwidth(dmfc);
-
- mutex_lock(&priv->mutex);
-
- if (slots > 8) {
- ret = -EBUSY;
- goto out;
- }
-
- /* For the MEM_BG channel, first try to allocate twice the slots */
- if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
- segment = dmfc_find_slots(priv, slots * 2);
- else if (slots < 2)
- /* Always allocate at least 128*4 bytes (2 slots) */
- slots = 2;
-
- if (segment >= 0)
- slots *= 2;
- else
- segment = dmfc_find_slots(priv, slots);
- if (segment < 0) {
- ret = -EBUSY;
- goto out;
- }
-
- ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
-
-out:
- mutex_unlock(&priv->mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
-
-int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
-{
- struct ipu_dmfc_priv *priv = dmfc->priv;
- u32 dmfc_gen1;
-
- dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
-
- if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
- dmfc_gen1 |= 1 << dmfc->data->eot_shift;
- else
- dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
-
- writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
-
-struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
-{
- struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
- int i;
-
- for (i = 0; i < DMFC_NUM_CHANNELS; i++)
- if (dmfcdata[i].ipu_channel == ipu_channel)
- return &priv->channels[i];
- return ERR_PTR(-ENODEV);
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_get);
-
-void ipu_dmfc_put(struct dmfc_channel *dmfc)
-{
- ipu_dmfc_free_bandwidth(dmfc);
-}
-EXPORT_SYMBOL_GPL(ipu_dmfc_put);
-
-int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
- struct clk *ipu_clk)
-{
- struct ipu_dmfc_priv *priv;
- int i;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->base = devm_ioremap(dev, base, PAGE_SIZE);
- if (!priv->base)
- return -ENOMEM;
-
- priv->dev = dev;
- priv->ipu = ipu;
- mutex_init(&priv->mutex);
-
- ipu->dmfc_priv = priv;
-
- for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
- priv->channels[i].priv = priv;
- priv->channels[i].ipu = ipu;
- priv->channels[i].data = &dmfcdata[i];
- }
-
- writel(0x0, priv->base + DMFC_WR_CHAN);
- writel(0x0, priv->base + DMFC_DP_CHAN);
-
- /*
- * We have a total bandwidth of clkrate * 4pixel divided
- * into 8 slots.
- */
- priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8;
-
- dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
- priv->bandwidth_per_slot / 1000000);
-
- writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
- writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
- writel(0x00000003, priv->base + DMFC_GENERAL1);
-
- return 0;
-}
-
-void ipu_dmfc_exit(struct ipu_soc *ipu)
-{
-}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
deleted file mode 100644
index 58f87c8d7c0..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/err.h>
-
-#include "imx-ipu-v3.h"
-#include "ipu-prv.h"
-
-#define DP_SYNC 0
-#define DP_ASYNC0 0x60
-#define DP_ASYNC1 0xBC
-
-#define DP_COM_CONF 0x0
-#define DP_GRAPH_WIND_CTRL 0x0004
-#define DP_FG_POS 0x0008
-#define DP_CSC_A_0 0x0044
-#define DP_CSC_A_1 0x0048
-#define DP_CSC_A_2 0x004C
-#define DP_CSC_A_3 0x0050
-#define DP_CSC_0 0x0054
-#define DP_CSC_1 0x0058
-
-#define DP_COM_CONF_FG_EN (1 << 0)
-#define DP_COM_CONF_GWSEL (1 << 1)
-#define DP_COM_CONF_GWAM (1 << 2)
-#define DP_COM_CONF_GWCKE (1 << 3)
-#define DP_COM_CONF_CSC_DEF_MASK (3 << 8)
-#define DP_COM_CONF_CSC_DEF_OFFSET 8
-#define DP_COM_CONF_CSC_DEF_FG (3 << 8)
-#define DP_COM_CONF_CSC_DEF_BG (2 << 8)
-#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8)
-
-#define IPUV3_NUM_FLOWS 3
-
-struct ipu_dp_priv;
-
-struct ipu_dp {
- u32 flow;
- bool in_use;
- bool foreground;
- enum ipu_color_space in_cs;
-};
-
-struct ipu_flow {
- struct ipu_dp foreground;
- struct ipu_dp background;
- enum ipu_color_space out_cs;
- void __iomem *base;
- struct ipu_dp_priv *priv;
-};
-
-struct ipu_dp_priv {
- struct ipu_soc *ipu;
- struct device *dev;
- void __iomem *base;
- struct ipu_flow flow[IPUV3_NUM_FLOWS];
- struct mutex mutex;
- int use_count;
-};
-
-static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
-
-static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
-{
- if (dp->foreground)
- return container_of(dp, struct ipu_flow, foreground);
- else
- return container_of(dp, struct ipu_flow, background);
-}
-
-int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
- u8 alpha, bool bg_chan)
-{
- struct ipu_flow *flow = to_flow(dp);
- struct ipu_dp_priv *priv = flow->priv;
- u32 reg;
-
- mutex_lock(&priv->mutex);
-
- reg = readl(flow->base + DP_COM_CONF);
- if (bg_chan)
- reg &= ~DP_COM_CONF_GWSEL;
- else
- reg |= DP_COM_CONF_GWSEL;
- writel(reg, flow->base + DP_COM_CONF);
-
- if (enable) {
- reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
- writel(reg | ((u32) alpha << 24),
- flow->base + DP_GRAPH_WIND_CTRL);
-
- reg = readl(flow->base + DP_COM_CONF);
- writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
- } else {
- reg = readl(flow->base + DP_COM_CONF);
- writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
- }
-
- ipu_srm_dp_sync_update(priv->ipu);
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
-
-int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
-{
- struct ipu_flow *flow = to_flow(dp);
- struct ipu_dp_priv *priv = flow->priv;
-
- writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
-
- ipu_srm_dp_sync_update(priv->ipu);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
-
-static void ipu_dp_csc_init(struct ipu_flow *flow,
- enum ipu_color_space in,
- enum ipu_color_space out,
- u32 place)
-{
- u32 reg;
-
- reg = readl(flow->base + DP_COM_CONF);
- reg &= ~DP_COM_CONF_CSC_DEF_MASK;
-
- if (in == out) {
- writel(reg, flow->base + DP_COM_CONF);
- return;
- }
-
- if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
- writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
- writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
- writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
- writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
- writel(0x3d6 | (0x0000 << 16) | (2 << 30),
- flow->base + DP_CSC_0);
- writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
- flow->base + DP_CSC_1);
- } else {
- writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
- writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
- writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
- writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
- writel(0x000 | (0x3e42 << 16) | (1 << 30),
- flow->base + DP_CSC_0);
- writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
- flow->base + DP_CSC_1);
- }
-
- reg |= place;
-
- writel(reg, flow->base + DP_COM_CONF);
-}
-
-int ipu_dp_setup_channel(struct ipu_dp *dp,
- enum ipu_color_space in,
- enum ipu_color_space out)
-{
- struct ipu_flow *flow = to_flow(dp);
- struct ipu_dp_priv *priv = flow->priv;
-
- mutex_lock(&priv->mutex);
-
- dp->in_cs = in;
-
- if (!dp->foreground)
- flow->out_cs = out;
-
- if (flow->foreground.in_cs == flow->background.in_cs) {
- /*
- * foreground and background are of same colorspace, put
- * colorspace converter after combining unit.
- */
- ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs,
- DP_COM_CONF_CSC_DEF_BOTH);
- } else {
- if (flow->foreground.in_cs == flow->out_cs)
- /*
- * foreground identical to output, apply color
- * conversion on background
- */
- ipu_dp_csc_init(flow, flow->background.in_cs,
- flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
- else
- ipu_dp_csc_init(flow, flow->foreground.in_cs,
- flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
- }
-
- ipu_srm_dp_sync_update(priv->ipu);
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
-
-int ipu_dp_enable_channel(struct ipu_dp *dp)
-{
- struct ipu_flow *flow = to_flow(dp);
- struct ipu_dp_priv *priv = flow->priv;
-
- mutex_lock(&priv->mutex);
-
- if (!priv->use_count)
- ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
-
- priv->use_count++;
-
- if (dp->foreground) {
- u32 reg;
-
- reg = readl(flow->base + DP_COM_CONF);
- reg |= DP_COM_CONF_FG_EN;
- writel(reg, flow->base + DP_COM_CONF);
-
- ipu_srm_dp_sync_update(priv->ipu);
- }
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
-
-void ipu_dp_disable_channel(struct ipu_dp *dp)
-{
- struct ipu_flow *flow = to_flow(dp);
- struct ipu_dp_priv *priv = flow->priv;
-
- mutex_lock(&priv->mutex);
-
- priv->use_count--;
-
- if (dp->foreground) {
- u32 reg, csc;
-
- reg = readl(flow->base + DP_COM_CONF);
- csc = reg & DP_COM_CONF_CSC_DEF_MASK;
- if (csc == DP_COM_CONF_CSC_DEF_FG)
- reg &= ~DP_COM_CONF_CSC_DEF_MASK;
-
- reg &= ~DP_COM_CONF_FG_EN;
- writel(reg, flow->base + DP_COM_CONF);
-
- writel(0, flow->base + DP_FG_POS);
- ipu_srm_dp_sync_update(priv->ipu);
- }
-
- if (!priv->use_count)
- ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
-
- if (priv->use_count < 0)
- priv->use_count = 0;
-
- mutex_unlock(&priv->mutex);
-}
-EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
-
-struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
-{
- struct ipu_dp_priv *priv = ipu->dp_priv;
- struct ipu_dp *dp;
-
- if ((flow >> 1) >= IPUV3_NUM_FLOWS)
- return ERR_PTR(-EINVAL);
-
- if (flow & 1)
- dp = &priv->flow[flow >> 1].foreground;
- else
- dp = &priv->flow[flow >> 1].background;
-
- if (dp->in_use)
- return ERR_PTR(-EBUSY);
-
- dp->in_use = true;
-
- return dp;
-}
-EXPORT_SYMBOL_GPL(ipu_dp_get);
-
-void ipu_dp_put(struct ipu_dp *dp)
-{
- dp->in_use = false;
-}
-EXPORT_SYMBOL_GPL(ipu_dp_put);
-
-int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
-{
- struct ipu_dp_priv *priv;
- int i;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- priv->dev = dev;
- priv->ipu = ipu;
-
- ipu->dp_priv = priv;
-
- priv->base = devm_ioremap(dev, base, PAGE_SIZE);
- if (!priv->base)
- return -ENOMEM;
-
- mutex_init(&priv->mutex);
-
- for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
- priv->flow[i].foreground.foreground = true;
- priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
- priv->flow[i].priv = priv;
- }
-
- return 0;
-}
-
-void ipu_dp_exit(struct ipu_soc *ipu)
-{
-}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
deleted file mode 100644
index 4df00501adc..00000000000
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
- * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-#ifndef __IPU_PRV_H__
-#define __IPU_PRV_H__
-
-struct ipu_soc;
-
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include "imx-ipu-v3.h"
-
-#define IPUV3_CHANNEL_CSI0 0
-#define IPUV3_CHANNEL_CSI1 1
-#define IPUV3_CHANNEL_CSI2 2
-#define IPUV3_CHANNEL_CSI3 3
-#define IPUV3_CHANNEL_MEM_BG_SYNC 23
-#define IPUV3_CHANNEL_MEM_FG_SYNC 27
-#define IPUV3_CHANNEL_MEM_DC_SYNC 28
-#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31
-#define IPUV3_CHANNEL_MEM_DC_ASYNC 41
-#define IPUV3_CHANNEL_ROT_ENC_MEM 45
-#define IPUV3_CHANNEL_ROT_VF_MEM 46
-#define IPUV3_CHANNEL_ROT_PP_MEM 47
-#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48
-#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49
-#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50
-#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51
-
-#define IPU_MCU_T_DEFAULT 8
-#define IPU_CM_IDMAC_REG_OFS 0x00008000
-#define IPU_CM_IC_REG_OFS 0x00020000
-#define IPU_CM_IRT_REG_OFS 0x00028000
-#define IPU_CM_CSI0_REG_OFS 0x00030000
-#define IPU_CM_CSI1_REG_OFS 0x00038000
-#define IPU_CM_SMFC_REG_OFS 0x00050000
-#define IPU_CM_DC_REG_OFS 0x00058000
-#define IPU_CM_DMFC_REG_OFS 0x00060000
-
-/* Register addresses */
-/* IPU Common registers */
-#define IPU_CM_REG(offset) (offset)
-
-#define IPU_CONF IPU_CM_REG(0)
-
-#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0)
-#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4)
-#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8)
-#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac)
-#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0)
-#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4)
-#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8)
-#define IPU_SKIP IPU_CM_REG(0x00bc)
-#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0)
-#define IPU_DISP_GEN IPU_CM_REG(0x00c4)
-#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8)
-#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc)
-#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0)
-#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4)
-#define IPU_SNOOP IPU_CM_REG(0x00d8)
-#define IPU_MEM_RST IPU_CM_REG(0x00dc)
-#define IPU_PM IPU_CM_REG(0x00e0)
-#define IPU_GPR IPU_CM_REG(0x00e4)
-#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
-#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
-#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32))
-#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244)
-#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248)
-#define IPU_SRM_STAT IPU_CM_REG(0x024C)
-#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250)
-#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254)
-#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
-#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
-#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
-#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
-
-#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
-#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
-
-#define IPU_DI0_COUNTER_RELEASE (1 << 24)
-#define IPU_DI1_COUNTER_RELEASE (1 << 25)
-
-#define IPU_IDMAC_REG(offset) (offset)
-
-#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
-#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
-#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c)
-#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
-#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
-#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
-#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024)
-#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028)
-#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c)
-#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030)
-#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034)
-#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
-#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
-
-#define IPU_NUM_IRQS (32 * 15)
-
-enum ipu_modules {
- IPU_CONF_CSI0_EN = (1 << 0),
- IPU_CONF_CSI1_EN = (1 << 1),
- IPU_CONF_IC_EN = (1 << 2),
- IPU_CONF_ROT_EN = (1 << 3),
- IPU_CONF_ISP_EN = (1 << 4),
- IPU_CONF_DP_EN = (1 << 5),
- IPU_CONF_DI0_EN = (1 << 6),
- IPU_CONF_DI1_EN = (1 << 7),
- IPU_CONF_SMFC_EN = (1 << 8),
- IPU_CONF_DC_EN = (1 << 9),
- IPU_CONF_DMFC_EN = (1 << 10),
-
- IPU_CONF_VDI_EN = (1 << 12),
-
- IPU_CONF_IDMAC_DIS = (1 << 22),
-
- IPU_CONF_IC_DMFC_SEL = (1 << 25),
- IPU_CONF_IC_DMFC_SYNC = (1 << 26),
- IPU_CONF_VDI_DMFC_SYNC = (1 << 27),
-
- IPU_CONF_CSI0_DATA_SOURCE = (1 << 28),
- IPU_CONF_CSI1_DATA_SOURCE = (1 << 29),
- IPU_CONF_IC_INPUT = (1 << 30),
- IPU_CONF_CSI_SEL = (1 << 31),
-};
-
-struct ipuv3_channel {
- unsigned int num;
-
- bool enabled;
- bool busy;
-
- struct ipu_soc *ipu;
-};
-
-struct ipu_dc_priv;
-struct ipu_dmfc_priv;
-struct ipu_di;
-struct ipu_devtype;
-
-struct ipu_soc {
- struct device *dev;
- const struct ipu_devtype *devtype;
- enum ipuv3_type ipu_type;
- spinlock_t lock;
- struct mutex channel_lock;
-
- void __iomem *cm_reg;
- void __iomem *idmac_reg;
- struct ipu_ch_param __iomem *cpmem_base;
-
- int usecount;
-
- struct clk *clk;
-
- struct ipuv3_channel channel[64];
-
- int irq_sync;
- int irq_err;
- struct irq_domain *domain;
-
- struct ipu_dc_priv *dc_priv;
- struct ipu_dp_priv *dp_priv;
- struct ipu_dmfc_priv *dmfc_priv;
- struct ipu_di *di_priv[2];
-};
-
-void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
-
-int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
-int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
-
-int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
- unsigned long base, u32 module, struct clk *ipu_clk);
-void ipu_di_exit(struct ipu_soc *ipu, int id);
-
-int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
- struct clk *ipu_clk);
-void ipu_dmfc_exit(struct ipu_soc *ipu);
-
-int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
-void ipu_dp_exit(struct ipu_soc *ipu);
-
-int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
- unsigned long template_base);
-void ipu_dc_exit(struct ipu_soc *ipu);
-
-int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
-void ipu_cpmem_exit(struct ipu_soc *ipu);
-
-#endif /* __IPU_PRV_H__ */
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 22be104fbda..720868bff35 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/device.h>
@@ -29,7 +30,7 @@
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
-#include "ipu-v3/imx-ipu-v3.h"
+#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
#include "ipuv3-plane.h"
@@ -59,24 +60,32 @@ struct ipu_crtc {
static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
{
+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
if (ipu_crtc->enabled)
return;
- ipu_di_enable(ipu_crtc->di);
- ipu_dc_enable_channel(ipu_crtc->dc);
+ ipu_dc_enable(ipu);
ipu_plane_enable(ipu_crtc->plane[0]);
+ /* Start DC channel and DI after IDMAC */
+ ipu_dc_enable_channel(ipu_crtc->dc);
+ ipu_di_enable(ipu_crtc->di);
ipu_crtc->enabled = 1;
}
static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
{
+ struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+
if (!ipu_crtc->enabled)
return;
- ipu_plane_disable(ipu_crtc->plane[0]);
+ /* Stop DC channel and DI before IDMAC */
ipu_dc_disable_channel(ipu_crtc->dc);
ipu_di_disable(ipu_crtc->di);
+ ipu_plane_disable(ipu_crtc->plane[0]);
+ ipu_dc_disable(ipu);
ipu_crtc->enabled = 0;
}
@@ -120,7 +129,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
ipu_crtc->newfb = fb;
ipu_crtc->page_flip_event = event;
- crtc->fb = fb;
+ crtc->primary->fb = fb;
return 0;
}
@@ -157,7 +166,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
sig_cfg.Vsync_pol = 1;
sig_cfg.enable_pol = 1;
- sig_cfg.clk_pol = 1;
+ sig_cfg.clk_pol = 0;
sig_cfg.width = mode->hdisplay;
sig_cfg.height = mode->vdisplay;
sig_cfg.pixel_fmt = out_pixel_fmt;
@@ -192,7 +201,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
return ret;
}
- return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
+ return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb,
0, 0, mode->hdisplay, mode->vdisplay,
x, y, mode->hdisplay, mode->vdisplay);
}
@@ -218,7 +227,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
if (ipu_crtc->newfb) {
ipu_crtc->newfb = NULL;
- ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb,
+ ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.primary->fb,
ipu_crtc->plane[0]->x, ipu_crtc->plane[0]->y);
ipu_crtc_handle_pageflip(ipu_crtc);
}
@@ -284,6 +293,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
IPU_DI_CLKMODE_EXT;
break;
+ case DRM_MODE_ENCODER_TMDS:
case DRM_MODE_ENCODER_NONE:
ipu_crtc->di_clkflags = 0;
break;
@@ -334,7 +344,7 @@ err_out:
}
static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
- struct ipu_client_platformdata *pdata)
+ struct ipu_client_platformdata *pdata, struct drm_device *drm)
{
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int dp = -EINVAL;
@@ -348,10 +358,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret;
}
- ret = imx_drm_add_crtc(&ipu_crtc->base,
- &ipu_crtc->imx_crtc,
- &ipu_crtc_helper_funcs, THIS_MODULE,
- ipu_crtc->dev->parent->of_node, pdata->di);
+ ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
+ &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
if (ret) {
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
goto err_put_resources;
@@ -399,43 +407,96 @@ err_put_resources:
return ret;
}
-static int ipu_drm_probe(struct platform_device *pdev)
+static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
+ int port_id)
{
- struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
- struct ipu_crtc *ipu_crtc;
- int ret;
+ struct device_node *port;
+ int id, ret;
+
+ port = of_get_child_by_name(parent, "port");
+ while (port) {
+ ret = of_property_read_u32(port, "reg", &id);
+ if (!ret && id == port_id)
+ return port;
+
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+ }
- if (!pdata)
- return -EINVAL;
+ return NULL;
+}
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
+{
+ struct ipu_client_platformdata *pdata = dev->platform_data;
+ struct drm_device *drm = data;
+ struct ipu_crtc *ipu_crtc;
+ int ret;
- ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+ ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
if (!ipu_crtc)
return -ENOMEM;
- ipu_crtc->dev = &pdev->dev;
+ ipu_crtc->dev = dev;
- ret = ipu_crtc_init(ipu_crtc, pdata);
+ ret = ipu_crtc_init(ipu_crtc, pdata, drm);
if (ret)
return ret;
- platform_set_drvdata(pdev, ipu_crtc);
+ dev_set_drvdata(dev, ipu_crtc);
return 0;
}
-static int ipu_drm_remove(struct platform_device *pdev)
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+ struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
imx_drm_remove_crtc(ipu_crtc->imx_crtc);
ipu_plane_put_resources(ipu_crtc->plane[0]);
ipu_put_resources(ipu_crtc);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+ .bind = ipu_drm_bind,
+ .unbind = ipu_drm_unbind,
+};
+
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ipu_client_platformdata *pdata = dev->platform_data;
+ int ret;
+
+ if (!dev->platform_data)
+ return -EINVAL;
+
+ if (!dev->of_node) {
+ /* Associate crtc device with the corresponding DI port node */
+ dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
+ pdata->di + 2);
+ if (!dev->of_node) {
+ dev_err(dev, "missing port@%d node in %s\n",
+ pdata->di + 2, dev->parent->of_node->full_name);
+ return -ENODEV;
+ }
+ }
+
+ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ return component_add(dev, &ipu_crtc_ops);
+}
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &ipu_crtc_ops);
return 0;
}
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 34b642a12f8..6f393a11f44 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -17,7 +17,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
-#include "ipu-v3/imx-ipu-v3.h"
+#include "video/imx-ipu-v3.h"
#include "ipuv3-plane.h"
#define to_ipu_plane(x) container_of(x, struct ipu_plane, base)
@@ -68,12 +68,12 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
if (!cma_obj) {
- DRM_LOG_KMS("entry is null.\n");
+ DRM_DEBUG_KMS("entry is null.\n");
return -EFAULT;
}
- dev_dbg(ipu_plane->base.dev->dev, "phys = 0x%x, x = %d, y = %d",
- cma_obj->paddr, x, y);
+ dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
+ &cma_obj->paddr, x, y);
cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
@@ -239,6 +239,8 @@ err_out:
void ipu_plane_enable(struct ipu_plane *ipu_plane)
{
+ if (ipu_plane->dp)
+ ipu_dp_enable(ipu_plane->ipu);
ipu_dmfc_enable_channel(ipu_plane->dmfc);
ipu_idmac_enable_channel(ipu_plane->ipu_ch);
if (ipu_plane->dp)
@@ -257,6 +259,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane)
ipu_dp_disable_channel(ipu_plane->dp);
ipu_idmac_disable_channel(ipu_plane->ipu_ch);
ipu_dmfc_disable_channel(ipu_plane->dmfc);
+ if (ipu_plane->dp)
+ ipu_dp_disable(ipu_plane->ipu);
}
static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode)
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 351d61dede0..4ca61afdf62 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -18,10 +18,12 @@
* MA 02110-1301, USA.
*/
+#include <linux/component.h>
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
#include <linux/videodev2.h>
#include <video/of_display_timing.h>
@@ -32,15 +34,14 @@
struct imx_parallel_display {
struct drm_connector connector;
- struct imx_drm_connector *imx_drm_connector;
struct drm_encoder encoder;
- struct imx_drm_encoder *imx_drm_encoder;
struct device *dev;
void *edid;
int edid_len;
u32 interface_pix_fmt;
int mode_valid;
struct drm_display_mode mode;
+ struct drm_panel *panel;
};
static enum drm_connector_status imx_pd_connector_detect(
@@ -49,17 +50,19 @@ static enum drm_connector_status imx_pd_connector_detect(
return connector_status_connected;
}
-static void imx_pd_connector_destroy(struct drm_connector *connector)
-{
- /* do not free here */
-}
-
static int imx_pd_connector_get_modes(struct drm_connector *connector)
{
struct imx_parallel_display *imxpd = con_to_imxpd(connector);
struct device_node *np = imxpd->dev->of_node;
int num_modes = 0;
+ if (imxpd->panel && imxpd->panel->funcs &&
+ imxpd->panel->funcs->get_modes) {
+ num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
+ if (num_modes > 0)
+ return num_modes;
+ }
+
if (imxpd->edid) {
drm_mode_connector_update_edid_property(connector, imxpd->edid);
num_modes = drm_add_edid_modes(connector, imxpd->edid);
@@ -67,6 +70,8 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (imxpd->mode_valid) {
struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
drm_mode_copy(mode, &imxpd->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
drm_mode_probed_add(connector, mode);
@@ -75,6 +80,8 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (np) {
struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE);
drm_mode_copy(mode, &imxpd->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
@@ -85,12 +92,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return num_modes;
}
-static int imx_pd_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- return 0;
-}
-
static struct drm_encoder *imx_pd_connector_best_encoder(
struct drm_connector *connector)
{
@@ -101,6 +102,12 @@ static struct drm_encoder *imx_pd_connector_best_encoder(
static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
{
+ struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
+
+ if (mode != DRM_MODE_DPMS_ON)
+ drm_panel_disable(imxpd->panel);
+ else
+ drm_panel_enable(imxpd->panel);
}
static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
@@ -114,8 +121,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
{
struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
- imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
- imxpd->interface_pix_fmt);
+ imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
}
static void imx_pd_encoder_commit(struct drm_encoder *encoder)
@@ -132,26 +138,20 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
-{
- /* do not free here */
-}
-
static struct drm_connector_funcs imx_pd_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_pd_connector_detect,
- .destroy = imx_pd_connector_destroy,
+ .destroy = imx_drm_connector_destroy,
};
static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
.get_modes = imx_pd_connector_get_modes,
.best_encoder = imx_pd_connector_best_encoder,
- .mode_valid = imx_pd_connector_mode_valid,
};
static struct drm_encoder_funcs imx_pd_encoder_funcs = {
- .destroy = imx_pd_encoder_destroy,
+ .destroy = imx_drm_encoder_destroy,
};
static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
@@ -163,51 +163,53 @@ static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
.disable = imx_pd_encoder_disable,
};
-static int imx_pd_register(struct imx_parallel_display *imxpd)
+static int imx_pd_register(struct drm_device *drm,
+ struct imx_parallel_display *imxpd)
{
int ret;
- drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
-
- imxpd->connector.funcs = &imx_pd_connector_funcs;
- imxpd->encoder.funcs = &imx_pd_encoder_funcs;
+ ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
+ imxpd->dev->of_node);
+ if (ret)
+ return ret;
- imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
- imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+ /* set the connector's dpms to OFF so that
+ * drm_helper_connector_dpms() won't return
+ * immediately since the current state is ON
+ * at this point.
+ */
+ imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
- ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
- THIS_MODULE);
- if (ret) {
- dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
- return ret;
- }
+ drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
+ DRM_MODE_ENCODER_NONE);
drm_connector_helper_add(&imxpd->connector,
&imx_pd_connector_helper_funcs);
+ drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
- ret = imx_drm_add_connector(&imxpd->connector,
- &imxpd->imx_drm_connector, THIS_MODULE);
- if (ret) {
- imx_drm_remove_encoder(imxpd->imx_drm_encoder);
- dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
- return ret;
- }
+ if (imxpd->panel)
+ drm_panel_attach(imxpd->panel, &imxpd->connector);
+
+ drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
imxpd->connector.encoder = &imxpd->encoder;
return 0;
}
-static int imx_pd_probe(struct platform_device *pdev)
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
{
- struct device_node *np = pdev->dev.of_node;
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
+ struct device_node *panel_node;
const u8 *edidp;
struct imx_parallel_display *imxpd;
int ret;
const char *fmt;
- imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+ imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
if (!imxpd)
return -ENOMEM;
@@ -223,32 +225,47 @@ static int imx_pd_probe(struct platform_device *pdev)
imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
else if (!strcmp(fmt, "bgr666"))
imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
+ else if (!strcmp(fmt, "lvds666"))
+ imxpd->interface_pix_fmt = v4l2_fourcc('L', 'V', 'D', '6');
}
- imxpd->dev = &pdev->dev;
+ panel_node = of_parse_phandle(np, "fsl,panel", 0);
+ if (panel_node)
+ imxpd->panel = of_drm_find_panel(panel_node);
- ret = imx_pd_register(imxpd);
+ imxpd->dev = dev;
+
+ ret = imx_pd_register(drm, imxpd);
if (ret)
return ret;
- ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
-
- platform_set_drvdata(pdev, imxpd);
+ dev_set_drvdata(dev, imxpd);
return 0;
}
-static int imx_pd_remove(struct platform_device *pdev)
+static void imx_pd_unbind(struct device *dev, struct device *master,
+ void *data)
{
- struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
- struct drm_connector *connector = &imxpd->connector;
- struct drm_encoder *encoder = &imxpd->encoder;
+ struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
- drm_mode_connector_detach_encoder(connector, encoder);
+ imxpd->encoder.funcs->destroy(&imxpd->encoder);
+ imxpd->connector.funcs->destroy(&imxpd->connector);
+}
- imx_drm_remove_connector(imxpd->imx_drm_connector);
- imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+static const struct component_ops imx_pd_ops = {
+ .bind = imx_pd_bind,
+ .unbind = imx_pd_unbind,
+};
+static int imx_pd_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_pd_ops);
+}
+
+static int imx_pd_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_pd_ops);
return 0;
}