提交 4551789f 编写于 作者: S Sean Paul 提交者: Inki Dae

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: NSean Paul <seanpaul@chromium.org>
Signed-off-by: NInki Dae <inki.dae@samsung.com>
上级 40c8ab4b
...@@ -97,6 +97,18 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops) ...@@ -97,6 +97,18 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
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) static bool drm_hdmi_is_connected(struct device *dev)
{ {
struct drm_hdmi_context *ctx = to_context(dev); struct drm_hdmi_context *ctx = to_context(dev);
...@@ -153,6 +165,7 @@ static int drm_hdmi_power_on(struct device *dev, int mode) ...@@ -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 = { static struct exynos_drm_display_ops drm_hdmi_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_HDMI, .type = EXYNOS_DISPLAY_TYPE_HDMI,
.initialize = drm_hdmi_display_initialize,
.is_connected = drm_hdmi_is_connected, .is_connected = drm_hdmi_is_connected,
.get_edid = drm_hdmi_get_edid, .get_edid = drm_hdmi_get_edid,
.check_mode = drm_hdmi_check_mode, .check_mode = drm_hdmi_check_mode,
...@@ -257,6 +270,21 @@ static void drm_hdmi_commit(struct device *subdrv_dev) ...@@ -257,6 +270,21 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
hdmi_ops->commit(ctx->hdmi_ctx->ctx); 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) static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
{ {
struct drm_hdmi_context *ctx = to_context(subdrv_dev); 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) ...@@ -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 = { static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
.initialize = drm_hdmi_mgr_initialize,
.dpms = drm_hdmi_dpms, .dpms = drm_hdmi_dpms,
.apply = drm_hdmi_apply, .apply = drm_hdmi_apply,
.enable_vblank = drm_hdmi_enable_vblank, .enable_vblank = drm_hdmi_enable_vblank,
...@@ -372,12 +401,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev, ...@@ -372,12 +401,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
ctx->hdmi_ctx = hdmi_ctx; ctx->hdmi_ctx = hdmi_ctx;
ctx->mixer_ctx = mixer_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; return 0;
} }
......
...@@ -23,12 +23,12 @@ ...@@ -23,12 +23,12 @@
* this context should be hdmi_context or mixer_context. * this context should be hdmi_context or mixer_context.
*/ */
struct exynos_drm_hdmi_context { struct exynos_drm_hdmi_context {
struct drm_device *drm_dev;
void *ctx; void *ctx;
}; };
struct exynos_hdmi_ops { struct exynos_hdmi_ops {
/* display */ /* display */
int (*initialize)(void *ctx, struct drm_device *drm_dev);
bool (*is_connected)(void *ctx); bool (*is_connected)(void *ctx);
struct edid *(*get_edid)(void *ctx, struct edid *(*get_edid)(void *ctx,
struct drm_connector *connector); struct drm_connector *connector);
...@@ -45,6 +45,7 @@ struct exynos_hdmi_ops { ...@@ -45,6 +45,7 @@ struct exynos_hdmi_ops {
struct exynos_mixer_ops { struct exynos_mixer_ops {
/* manager */ /* manager */
int (*initialize)(void *ctx, struct drm_device *drm_dev);
int (*iommu_on)(void *ctx, bool enable); int (*iommu_on)(void *ctx, bool enable);
int (*enable_vblank)(void *ctx, int pipe); int (*enable_vblank)(void *ctx, int pipe);
void (*disable_vblank)(void *ctx); void (*disable_vblank)(void *ctx);
......
...@@ -792,6 +792,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, ...@@ -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) static bool hdmi_is_connected(void *ctx)
{ {
struct hdmi_context *hdata = ctx; struct hdmi_context *hdata = ctx;
...@@ -1799,6 +1808,7 @@ static void hdmi_dpms(void *ctx, int mode) ...@@ -1799,6 +1808,7 @@ static void hdmi_dpms(void *ctx, int mode)
static struct exynos_hdmi_ops hdmi_ops = { static struct exynos_hdmi_ops hdmi_ops = {
/* display */ /* display */
.initialize = hdmi_initialize,
.is_connected = hdmi_is_connected, .is_connected = hdmi_is_connected,
.get_edid = hdmi_get_edid, .get_edid = hdmi_get_edid,
.check_mode = hdmi_check_mode, .check_mode = hdmi_check_mode,
...@@ -1819,8 +1829,8 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) ...@@ -1819,8 +1829,8 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
hdata->hpd = gpio_get_value(hdata->hpd_gpio); hdata->hpd = gpio_get_value(hdata->hpd_gpio);
mutex_unlock(&hdata->hdmi_mutex); mutex_unlock(&hdata->hdmi_mutex);
if (ctx->drm_dev) if (hdata->drm_dev)
drm_helper_hpd_irq_event(ctx->drm_dev); drm_helper_hpd_irq_event(hdata->drm_dev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -2078,8 +2088,8 @@ static int hdmi_suspend(struct device *dev) ...@@ -2078,8 +2088,8 @@ static int hdmi_suspend(struct device *dev)
disable_irq(hdata->irq); disable_irq(hdata->irq);
hdata->hpd = false; hdata->hpd = false;
if (ctx->drm_dev) if (hdata->drm_dev)
drm_helper_hpd_irq_event(ctx->drm_dev); drm_helper_hpd_irq_event(hdata->drm_dev);
if (pm_runtime_suspended(dev)) { if (pm_runtime_suspended(dev)) {
DRM_DEBUG_KMS("Already suspended\n"); DRM_DEBUG_KMS("Already suspended\n");
......
...@@ -82,6 +82,7 @@ enum mixer_version_id { ...@@ -82,6 +82,7 @@ enum mixer_version_id {
}; };
struct mixer_context { struct mixer_context {
struct platform_device *pdev;
struct device *dev; struct device *dev;
struct drm_device *drm_dev; struct drm_device *drm_dev;
int pipe; int pipe;
...@@ -685,20 +686,183 @@ static void mixer_win_reset(struct mixer_context *ctx) ...@@ -685,20 +686,183 @@ static void mixer_win_reset(struct mixer_context *ctx)
spin_unlock_irqrestore(&res->reg_slock, flags); 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) static int mixer_iommu_on(void *ctx, bool enable)
{ {
struct exynos_drm_hdmi_context *drm_hdmi_ctx;
struct mixer_context *mdata = ctx; struct mixer_context *mdata = ctx;
struct drm_device *drm_dev;
drm_hdmi_ctx = mdata->parent_ctx; if (is_drm_iommu_supported(mdata->drm_dev)) {
drm_dev = drm_hdmi_ctx->drm_dev;
if (is_drm_iommu_supported(drm_dev)) {
if (enable) 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; return 0;
} }
...@@ -970,6 +1134,7 @@ static void mixer_dpms(void *ctx, int mode) ...@@ -970,6 +1134,7 @@ static void mixer_dpms(void *ctx, int mode)
static struct exynos_mixer_ops mixer_ops = { static struct exynos_mixer_ops mixer_ops = {
/* manager */ /* manager */
.initialize = mixer_initialize,
.iommu_on = mixer_iommu_on, .iommu_on = mixer_iommu_on,
.enable_vblank = mixer_enable_vblank, .enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank, .disable_vblank = mixer_disable_vblank,
...@@ -983,153 +1148,6 @@ static struct exynos_mixer_ops mixer_ops = { ...@@ -983,153 +1148,6 @@ static struct exynos_mixer_ops mixer_ops = {
.check_mode = mixer_check_mode, .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 = { static struct mixer_drv_data exynos5420_mxr_drv_data = {
.version = MXR_VER_128_0_0_184, .version = MXR_VER_128_0_0_184,
.is_vp_enabled = 0, .is_vp_enabled = 0,
...@@ -1178,7 +1196,6 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1178,7 +1196,6 @@ static int mixer_probe(struct platform_device *pdev)
struct exynos_drm_hdmi_context *drm_hdmi_ctx; struct exynos_drm_hdmi_context *drm_hdmi_ctx;
struct mixer_context *ctx; struct mixer_context *ctx;
struct mixer_drv_data *drv; struct mixer_drv_data *drv;
int ret;
dev_info(dev, "probe start\n"); dev_info(dev, "probe start\n");
...@@ -1202,6 +1219,7 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1202,6 +1219,7 @@ static int mixer_probe(struct platform_device *pdev)
platform_get_device_id(pdev)->driver_data; platform_get_device_id(pdev)->driver_data;
} }
ctx->pdev = pdev;
ctx->dev = dev; ctx->dev = dev;
ctx->parent_ctx = (void *)drm_hdmi_ctx; ctx->parent_ctx = (void *)drm_hdmi_ctx;
drm_hdmi_ctx->ctx = (void *)ctx; drm_hdmi_ctx->ctx = (void *)ctx;
...@@ -1212,22 +1230,6 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1212,22 +1230,6 @@ static int mixer_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drm_hdmi_ctx); 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. */ /* attach mixer driver to common hdmi. */
exynos_mixer_drv_attach(drm_hdmi_ctx); exynos_mixer_drv_attach(drm_hdmi_ctx);
...@@ -1237,11 +1239,6 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1237,11 +1239,6 @@ static int mixer_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
return 0; return 0;
fail:
dev_info(dev, "probe failed\n");
return ret;
} }
static int mixer_remove(struct platform_device *pdev) static int mixer_remove(struct platform_device *pdev)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册