summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorSean Paul2014-01-30 22:19:05 +0100
committerInki Dae2014-03-23 16:36:28 +0100
commit4551789fcf3a1298c6bdc6c9ef23f9f6971612e3 (patch)
treeebcdb810081132c4613a1490f43cc45351ffc080 /drivers/gpu
parentdrm/exynos: Use manager_op initialize in fimd (diff)
downloadkernel-qcow2-linux-4551789fcf3a1298c6bdc6c9ef23f9f6971612e3.tar.gz
kernel-qcow2-linux-4551789fcf3a1298c6bdc6c9ef23f9f6971612e3.tar.xz
kernel-qcow2-linux-4551789fcf3a1298c6bdc6c9ef23f9f6971612e3.zip
drm/exynos: hdmi: Implement initialize op for hdmi
This patch implements the initialize callback in the hdmi and mixer manager. This allows us to get rid of drm_dev in the drm_hdmi level and track it in the mixer and hdmi drivers. This is one of the things holding back the complete removal of the drm_hdmi layer. Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c35
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c18
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c351
4 files changed, 219 insertions, 188 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index a1ef3c9aff69..aebcc0ecf71e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -97,6 +97,18 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
mixer_ops = ops;
}
+static int drm_hdmi_display_initialize(struct device *dev,
+ struct drm_device *drm_dev)
+{
+ struct drm_hdmi_context *ctx = to_context(dev);
+
+ if (hdmi_ops && hdmi_ops->initialize)
+ return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
+
+ return 0;
+}
+
+
static bool drm_hdmi_is_connected(struct device *dev)
{
struct drm_hdmi_context *ctx = to_context(dev);
@@ -153,6 +165,7 @@ static int drm_hdmi_power_on(struct device *dev, int mode)
static struct exynos_drm_display_ops drm_hdmi_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_HDMI,
+ .initialize = drm_hdmi_display_initialize,
.is_connected = drm_hdmi_is_connected,
.get_edid = drm_hdmi_get_edid,
.check_mode = drm_hdmi_check_mode,
@@ -257,6 +270,21 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
+static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
+ struct drm_device *drm_dev)
+{
+ struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ int ret = 0;
+
+ if (mixer_ops && mixer_ops->initialize)
+ ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev);
+
+ if (mixer_ops->iommu_on)
+ mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
+
+ return ret;
+}
+
static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -326,6 +354,7 @@ static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
}
static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
+ .initialize = drm_hdmi_mgr_initialize,
.dpms = drm_hdmi_dpms,
.apply = drm_hdmi_apply,
.enable_vblank = drm_hdmi_enable_vblank,
@@ -372,12 +401,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
ctx->hdmi_ctx = hdmi_ctx;
ctx->mixer_ctx = mixer_ctx;
- ctx->hdmi_ctx->drm_dev = drm_dev;
- ctx->mixer_ctx->drm_dev = drm_dev;
-
- if (mixer_ops->iommu_on)
- mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 724cab181976..cf7b1da67aba 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -23,12 +23,12 @@
* this context should be hdmi_context or mixer_context.
*/
struct exynos_drm_hdmi_context {
- struct drm_device *drm_dev;
void *ctx;
};
struct exynos_hdmi_ops {
/* display */
+ int (*initialize)(void *ctx, struct drm_device *drm_dev);
bool (*is_connected)(void *ctx);
struct edid *(*get_edid)(void *ctx,
struct drm_connector *connector);
@@ -45,6 +45,7 @@ struct exynos_hdmi_ops {
struct exynos_mixer_ops {
/* manager */
+ int (*initialize)(void *ctx, struct drm_device *drm_dev);
int (*iommu_on)(void *ctx, bool enable);
int (*enable_vblank)(void *ctx, int pipe);
void (*disable_vblank)(void *ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 9a98d902e75e..30eb54775ae3 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -792,6 +792,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
}
}
+static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
+{
+ struct hdmi_context *hdata = ctx;
+
+ hdata->drm_dev = drm_dev;
+
+ return 0;
+}
+
static bool hdmi_is_connected(void *ctx)
{
struct hdmi_context *hdata = ctx;
@@ -1799,6 +1808,7 @@ static void hdmi_dpms(void *ctx, int mode)
static struct exynos_hdmi_ops hdmi_ops = {
/* display */
+ .initialize = hdmi_initialize,
.is_connected = hdmi_is_connected,
.get_edid = hdmi_get_edid,
.check_mode = hdmi_check_mode,
@@ -1819,8 +1829,8 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
hdata->hpd = gpio_get_value(hdata->hpd_gpio);
mutex_unlock(&hdata->hdmi_mutex);
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ if (hdata->drm_dev)
+ drm_helper_hpd_irq_event(hdata->drm_dev);
return IRQ_HANDLED;
}
@@ -2078,8 +2088,8 @@ static int hdmi_suspend(struct device *dev)
disable_irq(hdata->irq);
hdata->hpd = false;
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ if (hdata->drm_dev)
+ drm_helper_hpd_irq_event(hdata->drm_dev);
if (pm_runtime_suspended(dev)) {
DRM_DEBUG_KMS("Already suspended\n");
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 53fd07691651..23b9407a6a05 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -82,6 +82,7 @@ enum mixer_version_id {
};
struct mixer_context {
+ struct platform_device *pdev;
struct device *dev;
struct drm_device *drm_dev;
int pipe;
@@ -685,20 +686,183 @@ static void mixer_win_reset(struct mixer_context *ctx)
spin_unlock_irqrestore(&res->reg_slock, flags);
}
+static irqreturn_t mixer_irq_handler(int irq, void *arg)
+{
+ struct mixer_context *ctx = arg;
+ struct mixer_resources *res = &ctx->mixer_res;
+ u32 val, base, shadow;
+
+ spin_lock(&res->reg_slock);
+
+ /* read interrupt status for handling and clearing flags for VSYNC */
+ val = mixer_reg_read(res, MXR_INT_STATUS);
+
+ /* handling VSYNC */
+ if (val & MXR_INT_STATUS_VSYNC) {
+ /* interlace scan need to check shadow register */
+ if (ctx->interlace) {
+ base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
+ shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
+ if (base != shadow)
+ goto out;
+
+ base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
+ shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
+ if (base != shadow)
+ goto out;
+ }
+
+ drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+ exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+
+ /* set wait vsync event to zero and wake up queue. */
+ if (atomic_read(&ctx->wait_vsync_event)) {
+ atomic_set(&ctx->wait_vsync_event, 0);
+ wake_up(&ctx->wait_vsync_queue);
+ }
+ }
+
+out:
+ /* clear interrupts */
+ if (~val & MXR_INT_EN_VSYNC) {
+ /* vsync interrupt use different bit for read and clear */
+ val &= ~MXR_INT_EN_VSYNC;
+ val |= MXR_INT_CLEAR_VSYNC;
+ }
+ mixer_reg_write(res, MXR_INT_STATUS, val);
+
+ spin_unlock(&res->reg_slock);
+
+ return IRQ_HANDLED;
+}
+
+static int mixer_resources_init(struct mixer_context *mixer_ctx)
+{
+ struct device *dev = &mixer_ctx->pdev->dev;
+ struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
+ struct resource *res;
+ int ret;
+
+ spin_lock_init(&mixer_res->reg_slock);
+
+ mixer_res->mixer = devm_clk_get(dev, "mixer");
+ if (IS_ERR(mixer_res->mixer)) {
+ dev_err(dev, "failed to get clock 'mixer'\n");
+ return -ENODEV;
+ }
+
+ mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
+ if (IS_ERR(mixer_res->sclk_hdmi)) {
+ dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+ return -ENODEV;
+ }
+ res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ return -ENXIO;
+ }
+
+ mixer_res->mixer_regs = devm_ioremap(dev, res->start,
+ resource_size(res));
+ if (mixer_res->mixer_regs == NULL) {
+ dev_err(dev, "register mapping failed.\n");
+ return -ENXIO;
+ }
+
+ res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "get interrupt resource failed.\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(dev, res->start, mixer_irq_handler,
+ 0, "drm_mixer", mixer_ctx);
+ if (ret) {
+ dev_err(dev, "request interrupt failed.\n");
+ return ret;
+ }
+ mixer_res->irq = res->start;
+
+ return 0;
+}
+
+static int vp_resources_init(struct mixer_context *mixer_ctx)
+{
+ struct device *dev = &mixer_ctx->pdev->dev;
+ struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
+ struct resource *res;
+
+ mixer_res->vp = devm_clk_get(dev, "vp");
+ if (IS_ERR(mixer_res->vp)) {
+ dev_err(dev, "failed to get clock 'vp'\n");
+ return -ENODEV;
+ }
+ mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
+ if (IS_ERR(mixer_res->sclk_mixer)) {
+ dev_err(dev, "failed to get clock 'sclk_mixer'\n");
+ return -ENODEV;
+ }
+ mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
+ if (IS_ERR(mixer_res->sclk_dac)) {
+ dev_err(dev, "failed to get clock 'sclk_dac'\n");
+ return -ENODEV;
+ }
+
+ if (mixer_res->sclk_hdmi)
+ clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
+
+ res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ return -ENXIO;
+ }
+
+ mixer_res->vp_regs = devm_ioremap(dev, res->start,
+ resource_size(res));
+ if (mixer_res->vp_regs == NULL) {
+ dev_err(dev, "register mapping failed.\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
+{
+ int ret;
+ struct mixer_context *mixer_ctx = ctx;
+
+ mixer_ctx->drm_dev = drm_dev;
+
+ /* acquire resources: regs, irqs, clocks */
+ ret = mixer_resources_init(mixer_ctx);
+ if (ret) {
+ DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
+ return ret;
+ }
+
+ if (mixer_ctx->vp_enabled) {
+ /* acquire vp resources: regs, irqs, clocks */
+ ret = vp_resources_init(mixer_ctx);
+ if (ret) {
+ DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
static int mixer_iommu_on(void *ctx, bool enable)
{
- struct exynos_drm_hdmi_context *drm_hdmi_ctx;
struct mixer_context *mdata = ctx;
- struct drm_device *drm_dev;
- drm_hdmi_ctx = mdata->parent_ctx;
- drm_dev = drm_hdmi_ctx->drm_dev;
-
- if (is_drm_iommu_supported(drm_dev)) {
+ if (is_drm_iommu_supported(mdata->drm_dev)) {
if (enable)
- return drm_iommu_attach_device(drm_dev, mdata->dev);
+ return drm_iommu_attach_device(mdata->drm_dev,
+ mdata->dev);
- drm_iommu_detach_device(drm_dev, mdata->dev);
+ drm_iommu_detach_device(mdata->drm_dev, mdata->dev);
}
return 0;
}
@@ -970,6 +1134,7 @@ static void mixer_dpms(void *ctx, int mode)
static struct exynos_mixer_ops mixer_ops = {
/* manager */
+ .initialize = mixer_initialize,
.iommu_on = mixer_iommu_on,
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
@@ -983,153 +1148,6 @@ static struct exynos_mixer_ops mixer_ops = {
.check_mode = mixer_check_mode,
};
-static irqreturn_t mixer_irq_handler(int irq, void *arg)
-{
- struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
- struct mixer_context *ctx = drm_hdmi_ctx->ctx;
- struct mixer_resources *res = &ctx->mixer_res;
- u32 val, base, shadow;
-
- spin_lock(&res->reg_slock);
-
- /* read interrupt status for handling and clearing flags for VSYNC */
- val = mixer_reg_read(res, MXR_INT_STATUS);
-
- /* handling VSYNC */
- if (val & MXR_INT_STATUS_VSYNC) {
- /* interlace scan need to check shadow register */
- if (ctx->interlace) {
- base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
- shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
- if (base != shadow)
- goto out;
-
- base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
- shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
- if (base != shadow)
- goto out;
- }
-
- drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
- exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
- ctx->pipe);
-
- /* set wait vsync event to zero and wake up queue. */
- if (atomic_read(&ctx->wait_vsync_event)) {
- atomic_set(&ctx->wait_vsync_event, 0);
- wake_up(&ctx->wait_vsync_queue);
- }
- }
-
-out:
- /* clear interrupts */
- if (~val & MXR_INT_EN_VSYNC) {
- /* vsync interrupt use different bit for read and clear */
- val &= ~MXR_INT_EN_VSYNC;
- val |= MXR_INT_CLEAR_VSYNC;
- }
- mixer_reg_write(res, MXR_INT_STATUS, val);
-
- spin_unlock(&res->reg_slock);
-
- return IRQ_HANDLED;
-}
-
-static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
- struct platform_device *pdev)
-{
- struct mixer_context *mixer_ctx = ctx->ctx;
- struct device *dev = &pdev->dev;
- struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
- struct resource *res;
- int ret;
-
- spin_lock_init(&mixer_res->reg_slock);
-
- mixer_res->mixer = devm_clk_get(dev, "mixer");
- if (IS_ERR(mixer_res->mixer)) {
- dev_err(dev, "failed to get clock 'mixer'\n");
- return -ENODEV;
- }
-
- mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
- if (IS_ERR(mixer_res->sclk_hdmi)) {
- dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
- return -ENODEV;
- }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(dev, "get memory resource failed.\n");
- return -ENXIO;
- }
-
- mixer_res->mixer_regs = devm_ioremap(dev, res->start,
- resource_size(res));
- if (mixer_res->mixer_regs == NULL) {
- dev_err(dev, "register mapping failed.\n");
- return -ENXIO;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- dev_err(dev, "get interrupt resource failed.\n");
- return -ENXIO;
- }
-
- ret = devm_request_irq(dev, res->start, mixer_irq_handler,
- 0, "drm_mixer", ctx);
- if (ret) {
- dev_err(dev, "request interrupt failed.\n");
- return ret;
- }
- mixer_res->irq = res->start;
-
- return 0;
-}
-
-static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
- struct platform_device *pdev)
-{
- struct mixer_context *mixer_ctx = ctx->ctx;
- struct device *dev = &pdev->dev;
- struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
- struct resource *res;
-
- mixer_res->vp = devm_clk_get(dev, "vp");
- if (IS_ERR(mixer_res->vp)) {
- dev_err(dev, "failed to get clock 'vp'\n");
- return -ENODEV;
- }
- mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
- if (IS_ERR(mixer_res->sclk_mixer)) {
- dev_err(dev, "failed to get clock 'sclk_mixer'\n");
- return -ENODEV;
- }
- mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
- if (IS_ERR(mixer_res->sclk_dac)) {
- dev_err(dev, "failed to get clock 'sclk_dac'\n");
- return -ENODEV;
- }
-
- if (mixer_res->sclk_hdmi)
- clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res == NULL) {
- dev_err(dev, "get memory resource failed.\n");
- return -ENXIO;
- }
-
- mixer_res->vp_regs = devm_ioremap(dev, res->start,
- resource_size(res));
- if (mixer_res->vp_regs == NULL) {
- dev_err(dev, "register mapping failed.\n");
- return -ENXIO;
- }
-
- return 0;
-}
-
static struct mixer_drv_data exynos5420_mxr_drv_data = {
.version = MXR_VER_128_0_0_184,
.is_vp_enabled = 0,
@@ -1178,7 +1196,6 @@ static int mixer_probe(struct platform_device *pdev)
struct exynos_drm_hdmi_context *drm_hdmi_ctx;
struct mixer_context *ctx;
struct mixer_drv_data *drv;
- int ret;
dev_info(dev, "probe start\n");
@@ -1202,6 +1219,7 @@ static int mixer_probe(struct platform_device *pdev)
platform_get_device_id(pdev)->driver_data;
}
+ ctx->pdev = pdev;
ctx->dev = dev;
ctx->parent_ctx = (void *)drm_hdmi_ctx;
drm_hdmi_ctx->ctx = (void *)ctx;
@@ -1212,22 +1230,6 @@ static int mixer_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drm_hdmi_ctx);
- /* acquire resources: regs, irqs, clocks */
- ret = mixer_resources_init(drm_hdmi_ctx, pdev);
- if (ret) {
- DRM_ERROR("mixer_resources_init failed\n");
- goto fail;
- }
-
- if (ctx->vp_enabled) {
- /* acquire vp resources: regs, irqs, clocks */
- ret = vp_resources_init(drm_hdmi_ctx, pdev);
- if (ret) {
- DRM_ERROR("vp_resources_init failed\n");
- goto fail;
- }
- }
-
/* attach mixer driver to common hdmi. */
exynos_mixer_drv_attach(drm_hdmi_ctx);
@@ -1237,11 +1239,6 @@ static int mixer_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
return 0;
-
-
-fail:
- dev_info(dev, "probe failed\n");
- return ret;
}
static int mixer_remove(struct platform_device *pdev)