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>
This commit is contained in:
Родитель
40c8ab4bcc
Коммит
4551789fcf
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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 @@
|
||||||
* 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 {
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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 {
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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 = {
|
||||||
.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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче