forked from Minki/linux
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Add Exynos4415 SoC support, some fixups and cleanups. Summary: - Resolve kernel lockup issue incurred by probe request in probe context. . For this, it moves all register codes of sub drivers into init function and adds component binding support for vidi driver. - Add Exynos4415 SoC support. - Make each manager and display object to be embedded in each driver context. - Fix and clean up FIMD and MIPI-DSI drivers. - Clean up unnecesary or wrong descriptions. - And trivial cleanups. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (58 commits) drm/exynos: avoid leak if exynos_dpi_probe() fails drm/exynos: Fix exynos_dpi_remove() parameter drm/exynos: vidi: add component support drm/exynos: fix exynos_drm_component_del drm/exynos/ipp: fix error return code drm/exynos: clean up machine compatible string check drm/exynos: move Exynos platform drivers registration to init Revert "drm/exynos: fix null pointer dereference issue" drm/exynos/dpi: stop using display->ctx pointer drm/exynos/dpi: embed display into private context drm/exynos/dp: stop using display->ctx pointer drm/exynos/dp: embed display into private context drm/exynos/vidi: stop using display->ctx pointer drm/exynos/vidi: embed display into private context drm/exynos/hdmi: stop using display->ctx pointer drm/exynos/hdmi: embed display into private context drm/exynos/fimd: stop using manager->ctx pointer drm/exynos/fimd: embed manager into private context drm/exynos/vidi: stop using manager->ctx pointer drm/exynos/vidi: embed manager into private context ...
This commit is contained in:
commit
0364d4fef4
@ -4,6 +4,7 @@ Required properties:
|
||||
- compatible: value should be one of the following
|
||||
"samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
|
||||
"samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
|
||||
"samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
|
||||
"samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
|
||||
- reg: physical base address and length of the registers set for the device
|
||||
- interrupts: should contain DSI interrupt
|
||||
|
@ -11,6 +11,7 @@ Required properties:
|
||||
"samsung,s5pv210-fimd"; /* for S5PV210 SoC */
|
||||
"samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
|
||||
"samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
|
||||
"samsung,exynos4415-fimd"; /* for Exynos4415 SoC */
|
||||
"samsung,exynos5250-fimd"; /* for Exynos5 SoCs */
|
||||
|
||||
- reg: physical base address and length of the FIMD registers set.
|
||||
|
@ -30,12 +30,17 @@
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/bridge/ptn3460.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_dp_core.h"
|
||||
|
||||
#define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \
|
||||
connector)
|
||||
|
||||
static inline struct exynos_dp_device *
|
||||
display_to_dp(struct exynos_drm_display *d)
|
||||
{
|
||||
return container_of(d, struct exynos_dp_device, display);
|
||||
}
|
||||
|
||||
struct bridge_init {
|
||||
struct i2c_client *client;
|
||||
struct device_node *node;
|
||||
@ -882,7 +887,7 @@ static void exynos_dp_hotplug(struct work_struct *work)
|
||||
|
||||
static void exynos_dp_commit(struct exynos_drm_display *display)
|
||||
{
|
||||
struct exynos_dp_device *dp = display->ctx;
|
||||
struct exynos_dp_device *dp = display_to_dp(display);
|
||||
int ret;
|
||||
|
||||
/* Keep the panel disabled while we configure video */
|
||||
@ -1020,7 +1025,7 @@ static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
|
||||
static int exynos_dp_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct exynos_dp_device *dp = display->ctx;
|
||||
struct exynos_dp_device *dp = display_to_dp(display);
|
||||
struct drm_connector *connector = &dp->connector;
|
||||
int ret;
|
||||
|
||||
@ -1052,33 +1057,19 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
|
||||
|
||||
static void exynos_dp_phy_init(struct exynos_dp_device *dp)
|
||||
{
|
||||
if (dp->phy) {
|
||||
if (dp->phy)
|
||||
phy_power_on(dp->phy);
|
||||
} else if (dp->phy_addr) {
|
||||
u32 reg;
|
||||
|
||||
reg = __raw_readl(dp->phy_addr);
|
||||
reg |= dp->enable_mask;
|
||||
__raw_writel(reg, dp->phy_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
|
||||
{
|
||||
if (dp->phy) {
|
||||
if (dp->phy)
|
||||
phy_power_off(dp->phy);
|
||||
} else if (dp->phy_addr) {
|
||||
u32 reg;
|
||||
|
||||
reg = __raw_readl(dp->phy_addr);
|
||||
reg &= ~(dp->enable_mask);
|
||||
__raw_writel(reg, dp->phy_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void exynos_dp_poweron(struct exynos_drm_display *display)
|
||||
{
|
||||
struct exynos_dp_device *dp = display->ctx;
|
||||
struct exynos_dp_device *dp = display_to_dp(display);
|
||||
|
||||
if (dp->dpms_mode == DRM_MODE_DPMS_ON)
|
||||
return;
|
||||
@ -1099,7 +1090,7 @@ static void exynos_dp_poweron(struct exynos_drm_display *display)
|
||||
|
||||
static void exynos_dp_poweroff(struct exynos_drm_display *display)
|
||||
{
|
||||
struct exynos_dp_device *dp = display->ctx;
|
||||
struct exynos_dp_device *dp = display_to_dp(display);
|
||||
|
||||
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
|
||||
return;
|
||||
@ -1124,7 +1115,7 @@ static void exynos_dp_poweroff(struct exynos_drm_display *display)
|
||||
|
||||
static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
|
||||
{
|
||||
struct exynos_dp_device *dp = display->ctx;
|
||||
struct exynos_dp_device *dp = display_to_dp(display);
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
@ -1147,11 +1138,6 @@ static struct exynos_drm_display_ops exynos_dp_display_ops = {
|
||||
.commit = exynos_dp_commit,
|
||||
};
|
||||
|
||||
static struct exynos_drm_display exynos_dp_display = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_LCD,
|
||||
.ops = &exynos_dp_display_ops,
|
||||
};
|
||||
|
||||
static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
|
||||
{
|
||||
struct device_node *dp_node = dev->of_node;
|
||||
@ -1210,44 +1196,6 @@ static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
|
||||
return dp_video_config;
|
||||
}
|
||||
|
||||
static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
|
||||
{
|
||||
struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
|
||||
u32 phy_base;
|
||||
int ret = 0;
|
||||
|
||||
dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
|
||||
if (!dp_phy_node) {
|
||||
dp->phy = devm_phy_get(dp->dev, "dp");
|
||||
return PTR_ERR_OR_ZERO(dp->phy);
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
|
||||
dev_err(dp->dev, "failed to get reg for dptx-phy\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
|
||||
&dp->enable_mask)) {
|
||||
dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dp->phy_addr = ioremap(phy_base, SZ_4);
|
||||
if (!dp->phy_addr) {
|
||||
dev_err(dp->dev, "failed to ioremap dp-phy\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
of_node_put(dp_phy_node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
|
||||
{
|
||||
int ret;
|
||||
@ -1263,10 +1211,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
|
||||
|
||||
static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct exynos_dp_device *dp = dev_get_drvdata(dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct resource *res;
|
||||
struct exynos_dp_device *dp = exynos_dp_display.ctx;
|
||||
unsigned int irq_flags;
|
||||
int ret = 0;
|
||||
|
||||
@ -1277,9 +1225,21 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
|
||||
if (IS_ERR(dp->video_info))
|
||||
return PTR_ERR(dp->video_info);
|
||||
|
||||
ret = exynos_dp_dt_parse_phydata(dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
dp->phy = devm_phy_get(dp->dev, "dp");
|
||||
if (IS_ERR(dp->phy)) {
|
||||
dev_err(dp->dev, "no DP phy configured\n");
|
||||
ret = PTR_ERR(dp->phy);
|
||||
if (ret) {
|
||||
/*
|
||||
* phy itself is not enabled, so we can move forward
|
||||
* assigning NULL to phy pointer.
|
||||
*/
|
||||
if (ret == -ENOSYS || ret == -ENODEV)
|
||||
dp->phy = NULL;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dp->panel) {
|
||||
ret = exynos_dp_dt_parse_panel(dp);
|
||||
@ -1346,17 +1306,15 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
|
||||
|
||||
dp->drm_dev = drm_dev;
|
||||
|
||||
platform_set_drvdata(pdev, &exynos_dp_display);
|
||||
|
||||
return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display);
|
||||
return exynos_drm_create_enc_conn(drm_dev, &dp->display);
|
||||
}
|
||||
|
||||
static void exynos_dp_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct exynos_drm_display *display = dev_get_drvdata(dev);
|
||||
struct exynos_dp_device *dp = dev_get_drvdata(dev);
|
||||
|
||||
exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
|
||||
exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static const struct component_ops exynos_dp_ops = {
|
||||
@ -1371,16 +1329,20 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
||||
struct exynos_dp_device *dp;
|
||||
int ret;
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
exynos_dp_display.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
|
||||
GFP_KERNEL);
|
||||
if (!dp)
|
||||
return -ENOMEM;
|
||||
|
||||
dp->display.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
dp->display.ops = &exynos_dp_display_ops;
|
||||
platform_set_drvdata(pdev, dp);
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
dp->display.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
panel_node = of_parse_phandle(dev->of_node, "panel", 0);
|
||||
if (panel_node) {
|
||||
dp->panel = of_drm_find_panel(panel_node);
|
||||
@ -1389,8 +1351,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
exynos_dp_display.ctx = dp;
|
||||
|
||||
ret = component_add(&pdev->dev, &exynos_dp_ops);
|
||||
if (ret)
|
||||
exynos_drm_component_del(&pdev->dev,
|
||||
@ -1410,19 +1370,17 @@ static int exynos_dp_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int exynos_dp_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos_drm_display *display = platform_get_drvdata(pdev);
|
||||
struct exynos_dp_device *dp = dev_get_drvdata(dev);
|
||||
|
||||
exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
|
||||
exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_dp_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos_drm_display *display = platform_get_drvdata(pdev);
|
||||
struct exynos_dp_device *dp = dev_get_drvdata(dev);
|
||||
|
||||
exynos_dp_dpms(display, DRM_MODE_DPMS_ON);
|
||||
exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
|
||||
#define DP_TIMEOUT_LOOP_COUNT 100
|
||||
#define MAX_CR_LOOP 5
|
||||
#define MAX_EQ_LOOP 5
|
||||
@ -145,6 +147,7 @@ struct link_train {
|
||||
};
|
||||
|
||||
struct exynos_dp_device {
|
||||
struct exynos_drm_display display;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector connector;
|
||||
@ -153,8 +156,6 @@ struct exynos_dp_device {
|
||||
struct clk *clock;
|
||||
unsigned int irq;
|
||||
void __iomem *reg_base;
|
||||
void __iomem *phy_addr;
|
||||
unsigned int enable_mask;
|
||||
|
||||
struct video_info *video_info;
|
||||
struct link_train link_train;
|
||||
|
@ -15,10 +15,7 @@
|
||||
#ifndef _EXYNOS_DRM_CRTC_H_
|
||||
#define _EXYNOS_DRM_CRTC_H_
|
||||
|
||||
struct drm_device;
|
||||
struct drm_crtc;
|
||||
struct exynos_drm_manager;
|
||||
struct exynos_drm_overlay;
|
||||
#include "exynos_drm_drv.h"
|
||||
|
||||
int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
|
||||
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "exynos_drm_drv.h"
|
||||
|
||||
struct exynos_dpi {
|
||||
struct exynos_drm_display display;
|
||||
struct device *dev;
|
||||
struct device_node *panel_node;
|
||||
|
||||
@ -35,6 +36,11 @@ struct exynos_dpi {
|
||||
|
||||
#define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
|
||||
|
||||
static inline struct exynos_dpi *display_to_dpi(struct exynos_drm_display *d)
|
||||
{
|
||||
return container_of(d, struct exynos_dpi, display);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
exynos_dpi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
@ -100,7 +106,7 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
|
||||
static int exynos_dpi_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct exynos_dpi *ctx = display->ctx;
|
||||
struct exynos_dpi *ctx = display_to_dpi(display);
|
||||
struct drm_connector *connector = &ctx->connector;
|
||||
int ret;
|
||||
|
||||
@ -141,7 +147,7 @@ static void exynos_dpi_poweroff(struct exynos_dpi *ctx)
|
||||
|
||||
static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
|
||||
{
|
||||
struct exynos_dpi *ctx = display->ctx;
|
||||
struct exynos_dpi *ctx = display_to_dpi(display);
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
@ -165,11 +171,6 @@ static struct exynos_drm_display_ops exynos_dpi_display_ops = {
|
||||
.dpms = exynos_dpi_dpms
|
||||
};
|
||||
|
||||
static struct exynos_drm_display exynos_dpi_display = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_LCD,
|
||||
.ops = &exynos_dpi_display_ops,
|
||||
};
|
||||
|
||||
/* of_* functions will be removed after merge of of_graph patches */
|
||||
static struct device_node *
|
||||
of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
|
||||
@ -299,20 +300,21 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
|
||||
struct exynos_dpi *ctx;
|
||||
int ret;
|
||||
|
||||
ret = exynos_drm_component_add(dev,
|
||||
EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
exynos_dpi_display.type);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
goto err_del_component;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ctx->display.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
ctx->display.ops = &exynos_dpi_display_ops;
|
||||
ctx->dev = dev;
|
||||
exynos_dpi_display.ctx = ctx;
|
||||
ctx->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
ret = exynos_drm_component_add(dev,
|
||||
EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
ctx->display.type);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = exynos_dpi_parse_dt(ctx);
|
||||
if (ret < 0) {
|
||||
devm_kfree(dev, ctx);
|
||||
@ -328,7 +330,7 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
return &exynos_dpi_display;
|
||||
return &ctx->display;
|
||||
|
||||
err_del_component:
|
||||
exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
@ -336,16 +338,16 @@ err_del_component:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int exynos_dpi_remove(struct device *dev)
|
||||
int exynos_dpi_remove(struct exynos_drm_display *display)
|
||||
{
|
||||
struct exynos_dpi *ctx = exynos_dpi_display.ctx;
|
||||
struct exynos_dpi *ctx = display_to_dpi(display);
|
||||
|
||||
exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
|
||||
exynos_dpi_dpms(&ctx->display, DRM_MODE_DPMS_OFF);
|
||||
|
||||
if (ctx->panel)
|
||||
drm_panel_detach(ctx->panel);
|
||||
|
||||
exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
exynos_drm_component_del(ctx->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -203,8 +203,6 @@ static int exynos_drm_resume(struct drm_device *dev)
|
||||
}
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
drm_helper_resume_force_mode(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -475,8 +473,6 @@ void exynos_drm_component_del(struct device *dev,
|
||||
list_del(&cdev->list);
|
||||
kfree(cdev);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&drm_component_lock);
|
||||
@ -495,6 +491,12 @@ static struct component_match *exynos_drm_match_add(struct device *dev)
|
||||
|
||||
mutex_lock(&drm_component_lock);
|
||||
|
||||
/* Do not retry to probe if there is no any kms driver regitered. */
|
||||
if (list_empty(&drm_component_list)) {
|
||||
mutex_unlock(&drm_component_lock);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
list_for_each_entry(cdev, &drm_component_list, list) {
|
||||
/*
|
||||
* Add components to master only in case that crtc and
|
||||
@ -550,183 +552,68 @@ static const struct component_master_ops exynos_drm_ops = {
|
||||
.unbind = exynos_drm_unbind,
|
||||
};
|
||||
|
||||
static struct platform_driver *const exynos_drm_kms_drivers[] = {
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
&fimd_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_DP
|
||||
&dp_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_DSI
|
||||
&dsi_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
&mixer_driver,
|
||||
&hdmi_driver,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
|
||||
#ifdef CONFIG_DRM_EXYNOS_G2D
|
||||
&g2d_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMC
|
||||
&fimc_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
|
||||
&rotator_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_GSC
|
||||
&gsc_driver,
|
||||
#endif
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
&ipp_driver,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int exynos_drm_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct component_match *match;
|
||||
int ret;
|
||||
|
||||
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
ret = platform_driver_register(&fimd_driver);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DP
|
||||
ret = platform_driver_register(&dp_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_fimd_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DSI
|
||||
ret = platform_driver_register(&dsi_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_dp_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
ret = platform_driver_register(&mixer_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_dsi_drv;
|
||||
ret = platform_driver_register(&hdmi_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_mixer_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_G2D
|
||||
ret = platform_driver_register(&g2d_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_hdmi_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMC
|
||||
ret = platform_driver_register(&fimc_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_g2d_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
|
||||
ret = platform_driver_register(&rotator_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_fimc_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_GSC
|
||||
ret = platform_driver_register(&gsc_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_rotator_drv;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
ret = platform_driver_register(&ipp_driver);
|
||||
if (ret < 0)
|
||||
goto err_unregister_gsc_drv;
|
||||
|
||||
ret = exynos_platform_device_ipp_register();
|
||||
if (ret < 0)
|
||||
goto err_unregister_ipp_drv;
|
||||
#endif
|
||||
|
||||
match = exynos_drm_match_add(&pdev->dev);
|
||||
if (IS_ERR(match)) {
|
||||
ret = PTR_ERR(match);
|
||||
goto err_unregister_resources;
|
||||
return PTR_ERR(match);
|
||||
}
|
||||
|
||||
ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
|
||||
match);
|
||||
if (ret < 0)
|
||||
goto err_unregister_resources;
|
||||
|
||||
return ret;
|
||||
|
||||
err_unregister_resources:
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
exynos_platform_device_ipp_unregister();
|
||||
err_unregister_ipp_drv:
|
||||
platform_driver_unregister(&ipp_driver);
|
||||
err_unregister_gsc_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_GSC
|
||||
platform_driver_unregister(&gsc_driver);
|
||||
err_unregister_rotator_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
|
||||
platform_driver_unregister(&rotator_driver);
|
||||
err_unregister_fimc_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMC
|
||||
platform_driver_unregister(&fimc_driver);
|
||||
err_unregister_g2d_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_G2D
|
||||
platform_driver_unregister(&g2d_driver);
|
||||
err_unregister_hdmi_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
err_unregister_mixer_drv:
|
||||
platform_driver_unregister(&mixer_driver);
|
||||
err_unregister_dsi_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DSI
|
||||
platform_driver_unregister(&dsi_driver);
|
||||
err_unregister_dp_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DP
|
||||
platform_driver_unregister(&dp_driver);
|
||||
err_unregister_fimd_drv:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
#endif
|
||||
return ret;
|
||||
return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
|
||||
match);
|
||||
}
|
||||
|
||||
static int exynos_drm_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
exynos_platform_device_ipp_unregister();
|
||||
platform_driver_unregister(&ipp_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_GSC
|
||||
platform_driver_unregister(&gsc_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
|
||||
platform_driver_unregister(&rotator_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMC
|
||||
platform_driver_unregister(&fimc_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_G2D
|
||||
platform_driver_unregister(&g2d_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_HDMI
|
||||
platform_driver_unregister(&mixer_driver);
|
||||
platform_driver_unregister(&hdmi_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_FIMD
|
||||
platform_driver_unregister(&fimd_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DSI
|
||||
platform_driver_unregister(&dsi_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DP
|
||||
platform_driver_unregister(&dp_driver);
|
||||
#endif
|
||||
component_master_del(&pdev->dev, &exynos_drm_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const strings[] = {
|
||||
"samsung,exynos3",
|
||||
"samsung,exynos4",
|
||||
"samsung,exynos5",
|
||||
};
|
||||
|
||||
static struct platform_driver exynos_drm_platform_driver = {
|
||||
.probe = exynos_drm_platform_probe,
|
||||
.remove = exynos_drm_platform_remove,
|
||||
@ -739,31 +626,75 @@ static struct platform_driver exynos_drm_platform_driver = {
|
||||
|
||||
static int exynos_drm_init(void)
|
||||
{
|
||||
int ret;
|
||||
bool is_exynos = false;
|
||||
int ret, i, j;
|
||||
|
||||
/*
|
||||
* Register device object only in case of Exynos SoC.
|
||||
*
|
||||
* Below codes resolves temporarily infinite loop issue incurred
|
||||
* by Exynos drm driver when using multi-platform kernel.
|
||||
* So these codes will be replaced with more generic way later.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(strings); i++) {
|
||||
if (of_machine_is_compatible(strings[i])) {
|
||||
is_exynos = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_exynos)
|
||||
return -ENODEV;
|
||||
|
||||
exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
|
||||
NULL, 0);
|
||||
if (IS_ERR(exynos_drm_pdev))
|
||||
return PTR_ERR(exynos_drm_pdev);
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
ret = exynos_drm_probe_vidi();
|
||||
if (ret < 0)
|
||||
goto err_unregister_pd;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) {
|
||||
ret = platform_driver_register(exynos_drm_kms_drivers[i]);
|
||||
if (ret < 0)
|
||||
goto err_unregister_kms_drivers;
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) {
|
||||
ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
|
||||
if (ret < 0)
|
||||
goto err_unregister_non_kms_drivers;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
ret = exynos_platform_device_ipp_register();
|
||||
if (ret < 0)
|
||||
goto err_unregister_non_kms_drivers;
|
||||
#endif
|
||||
|
||||
ret = platform_driver_register(&exynos_drm_platform_driver);
|
||||
if (ret)
|
||||
goto err_remove_vidi;
|
||||
goto err_unregister_resources;
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_vidi:
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
err_unregister_resources:
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
exynos_platform_device_ipp_unregister();
|
||||
#endif
|
||||
|
||||
err_unregister_non_kms_drivers:
|
||||
while (--j >= 0)
|
||||
platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
|
||||
|
||||
err_unregister_kms_drivers:
|
||||
while (--i >= 0)
|
||||
platform_driver_unregister(exynos_drm_kms_drivers[i]);
|
||||
|
||||
exynos_drm_remove_vidi();
|
||||
|
||||
err_unregister_pd:
|
||||
#endif
|
||||
platform_device_unregister(exynos_drm_pdev);
|
||||
|
||||
return ret;
|
||||
@ -771,10 +702,22 @@ err_unregister_pd:
|
||||
|
||||
static void exynos_drm_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&exynos_drm_platform_driver);
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
exynos_drm_remove_vidi();
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
exynos_platform_device_ipp_unregister();
|
||||
#endif
|
||||
|
||||
for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i)
|
||||
platform_driver_unregister(exynos_drm_non_kms_drivers[i]);
|
||||
|
||||
for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i)
|
||||
platform_driver_unregister(exynos_drm_kms_drivers[i]);
|
||||
|
||||
platform_driver_unregister(&exynos_drm_platform_driver);
|
||||
|
||||
exynos_drm_remove_vidi();
|
||||
|
||||
platform_device_unregister(exynos_drm_pdev);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#ifndef _EXYNOS_DRM_DRV_H_
|
||||
#define _EXYNOS_DRM_DRV_H_
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define MAX_CRTC 3
|
||||
@ -22,24 +23,6 @@
|
||||
#define MAX_FB_BUFFER 4
|
||||
#define DEFAULT_ZPOS -1
|
||||
|
||||
#define _wait_for(COND, MS) ({ \
|
||||
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
|
||||
int ret__ = 0; \
|
||||
while (!(COND)) { \
|
||||
if (time_after(jiffies, timeout__)) { \
|
||||
ret__ = -ETIMEDOUT; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
ret__; \
|
||||
})
|
||||
|
||||
#define wait_for(COND, MS) _wait_for(COND, MS)
|
||||
|
||||
struct drm_device;
|
||||
struct exynos_drm_overlay;
|
||||
struct drm_connector;
|
||||
|
||||
/* This enumerates device type. */
|
||||
enum exynos_drm_device_type {
|
||||
EXYNOS_DEVICE_TYPE_NONE,
|
||||
@ -83,10 +66,10 @@ enum exynos_drm_output_type {
|
||||
* @dma_addr: array of bus(accessed by dma) address to the memory region
|
||||
* allocated for a overlay.
|
||||
* @zpos: order of overlay layer(z position).
|
||||
* @default_win: a window to be enabled.
|
||||
* @color_key: color key on or off.
|
||||
* @index_color: if using color key feature then this value would be used
|
||||
* as index color.
|
||||
* @default_win: a window to be enabled.
|
||||
* @color_key: color key on or off.
|
||||
* @local_path: in case of lcd type, local path mode on or off.
|
||||
* @transparency: transparency on or off.
|
||||
* @activated: activated or not.
|
||||
@ -114,19 +97,20 @@ struct exynos_drm_overlay {
|
||||
uint32_t pixel_format;
|
||||
dma_addr_t dma_addr[MAX_FB_BUFFER];
|
||||
int zpos;
|
||||
|
||||
bool default_win;
|
||||
bool color_key;
|
||||
unsigned int index_color;
|
||||
bool local_path;
|
||||
bool transparency;
|
||||
bool activated;
|
||||
|
||||
bool default_win:1;
|
||||
bool color_key:1;
|
||||
bool local_path:1;
|
||||
bool transparency:1;
|
||||
bool activated:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos DRM Display Structure.
|
||||
* - this structure is common to analog tv, digital tv and lcd panel.
|
||||
*
|
||||
* @create_connector: initialize and register a new connector
|
||||
* @remove: cleans up the display for removal
|
||||
* @mode_fixup: fix mode data comparing to hw specific display mode.
|
||||
* @mode_set: convert drm_display_mode to hw specific display mode and
|
||||
@ -168,7 +152,6 @@ struct exynos_drm_display {
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
struct exynos_drm_display_ops *ops;
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -227,7 +210,6 @@ struct exynos_drm_manager {
|
||||
struct drm_crtc *crtc;
|
||||
int pipe;
|
||||
struct exynos_drm_manager_ops *ops;
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
struct exynos_drm_g2d_private {
|
||||
@ -279,8 +261,6 @@ struct exynos_drm_private {
|
||||
* @dev: pointer to device object for subdrv device driver.
|
||||
* @drm_dev: pointer to drm_device and this pointer would be set
|
||||
* when sub driver calls exynos_drm_subdrv_register().
|
||||
* @manager: subdrv has its own manager to control a hardware appropriately
|
||||
* and we can access a hardware drawing on this manager.
|
||||
* @probe: this callback would be called by exynos drm driver after
|
||||
* subdrv is registered to it.
|
||||
* @remove: this callback is used to release resources created
|
||||
@ -312,45 +292,34 @@ int exynos_drm_device_subdrv_remove(struct drm_device *dev);
|
||||
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
|
||||
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
|
||||
|
||||
/*
|
||||
* this function registers exynos drm hdmi platform device. It ensures only one
|
||||
* instance of the device is created.
|
||||
*/
|
||||
int exynos_platform_device_hdmi_register(void);
|
||||
|
||||
/*
|
||||
* this function unregisters exynos drm hdmi platform device if it exists.
|
||||
*/
|
||||
void exynos_platform_device_hdmi_unregister(void);
|
||||
|
||||
/*
|
||||
* this function registers exynos drm ipp platform device.
|
||||
*/
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
int exynos_platform_device_ipp_register(void);
|
||||
|
||||
/*
|
||||
* this function unregisters exynos drm ipp platform device if it exists.
|
||||
*/
|
||||
void exynos_platform_device_ipp_unregister(void);
|
||||
#else
|
||||
static inline int exynos_platform_device_ipp_register(void) { return 0; }
|
||||
static inline void exynos_platform_device_ipp_unregister(void) {}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_DPI
|
||||
struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
|
||||
int exynos_dpi_remove(struct device *dev);
|
||||
int exynos_dpi_remove(struct exynos_drm_display *display);
|
||||
#else
|
||||
static inline struct exynos_drm_display *
|
||||
exynos_dpi_probe(struct device *dev) { return NULL; }
|
||||
static inline int exynos_dpi_remove(struct device *dev) { return 0; }
|
||||
static inline int exynos_dpi_remove(struct exynos_drm_display *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* this function registers exynos drm vidi platform device/driver.
|
||||
*/
|
||||
#ifdef CONFIG_DRM_EXYNOS_VIDI
|
||||
int exynos_drm_probe_vidi(void);
|
||||
|
||||
/*
|
||||
* this function unregister exynos drm vidi platform device/driver.
|
||||
*/
|
||||
void exynos_drm_remove_vidi(void);
|
||||
#else
|
||||
static inline int exynos_drm_probe_vidi(void) { return 0; }
|
||||
static inline void exynos_drm_remove_vidi(void) {}
|
||||
#endif
|
||||
|
||||
/* This function creates a encoder and a connector, and initializes them. */
|
||||
int exynos_drm_create_enc_conn(struct drm_device *dev,
|
||||
|
@ -268,9 +268,9 @@ struct exynos_dsi_driver_data {
|
||||
};
|
||||
|
||||
struct exynos_dsi {
|
||||
struct exynos_drm_display display;
|
||||
struct mipi_dsi_host dsi_host;
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct device_node *panel_node;
|
||||
struct drm_panel *panel;
|
||||
struct device *dev;
|
||||
@ -304,6 +304,11 @@ struct exynos_dsi {
|
||||
#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
|
||||
#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
|
||||
|
||||
static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d)
|
||||
{
|
||||
return container_of(d, struct exynos_dsi, display);
|
||||
}
|
||||
|
||||
static struct exynos_dsi_driver_data exynos3_dsi_driver_data = {
|
||||
.plltmr_reg = 0x50,
|
||||
.has_freqband = 1,
|
||||
@ -316,6 +321,11 @@ static struct exynos_dsi_driver_data exynos4_dsi_driver_data = {
|
||||
.has_clklane_stop = 1,
|
||||
};
|
||||
|
||||
static struct exynos_dsi_driver_data exynos4415_dsi_driver_data = {
|
||||
.plltmr_reg = 0x58,
|
||||
.has_clklane_stop = 1,
|
||||
};
|
||||
|
||||
static struct exynos_dsi_driver_data exynos5_dsi_driver_data = {
|
||||
.plltmr_reg = 0x58,
|
||||
};
|
||||
@ -325,6 +335,8 @@ static struct of_device_id exynos_dsi_of_match[] = {
|
||||
.data = &exynos3_dsi_driver_data },
|
||||
{ .compatible = "samsung,exynos4210-mipi-dsi",
|
||||
.data = &exynos4_dsi_driver_data },
|
||||
{ .compatible = "samsung,exynos4415-mipi-dsi",
|
||||
.data = &exynos4415_dsi_driver_data },
|
||||
{ .compatible = "samsung,exynos5410-mipi-dsi",
|
||||
.data = &exynos5_dsi_driver_data },
|
||||
{ }
|
||||
@ -1104,7 +1116,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
|
||||
static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
|
||||
struct drm_encoder *encoder = dsi->encoder;
|
||||
struct drm_encoder *encoder = dsi->display.encoder;
|
||||
|
||||
if (dsi->state & DSIM_STATE_ENABLED)
|
||||
exynos_drm_crtc_te_handler(encoder->crtc);
|
||||
@ -1143,6 +1155,7 @@ static int exynos_dsi_init(struct exynos_dsi *dsi)
|
||||
static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi)
|
||||
{
|
||||
int ret;
|
||||
int te_gpio_irq;
|
||||
|
||||
dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0);
|
||||
if (!gpio_is_valid(dsi->te_gpio)) {
|
||||
@ -1157,14 +1170,10 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* This TE GPIO IRQ should not be set to IRQ_NOAUTOEN, because panel
|
||||
* calls drm_panel_init() first then calls mipi_dsi_attach() in probe().
|
||||
* It means that te_gpio is invalid when exynos_dsi_enable_irq() is
|
||||
* called by drm_panel_init() before panel is attached.
|
||||
*/
|
||||
ret = request_threaded_irq(gpio_to_irq(dsi->te_gpio),
|
||||
exynos_dsi_te_irq_handler, NULL,
|
||||
te_gpio_irq = gpio_to_irq(dsi->te_gpio);
|
||||
|
||||
irq_set_status_flags(te_gpio_irq, IRQ_NOAUTOEN);
|
||||
ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL,
|
||||
IRQF_TRIGGER_RISING, "TE", dsi);
|
||||
if (ret) {
|
||||
dev_err(dsi->dev, "request interrupt failed with %d\n", ret);
|
||||
@ -1195,9 +1204,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
|
||||
dsi->mode_flags = device->mode_flags;
|
||||
dsi->panel_node = device->dev.of_node;
|
||||
|
||||
if (dsi->connector.dev)
|
||||
drm_helper_hpd_irq_event(dsi->connector.dev);
|
||||
|
||||
/*
|
||||
* This is a temporary solution and should be made by more generic way.
|
||||
*
|
||||
@ -1211,6 +1217,9 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dsi->connector.dev)
|
||||
drm_helper_hpd_irq_event(dsi->connector.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1369,16 +1378,17 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
|
||||
exynos_dsi_set_display_mode(dsi);
|
||||
exynos_dsi_set_display_enable(dsi, true);
|
||||
|
||||
dsi->state |= DSIM_STATE_ENABLED;
|
||||
|
||||
ret = drm_panel_enable(dsi->panel);
|
||||
if (ret < 0) {
|
||||
dsi->state &= ~DSIM_STATE_ENABLED;
|
||||
exynos_dsi_set_display_enable(dsi, false);
|
||||
drm_panel_unprepare(dsi->panel);
|
||||
exynos_dsi_poweroff(dsi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dsi->state |= DSIM_STATE_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1397,7 +1407,7 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi)
|
||||
|
||||
static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode)
|
||||
{
|
||||
struct exynos_dsi *dsi = display->ctx;
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
|
||||
if (dsi->panel) {
|
||||
switch (mode) {
|
||||
@ -1474,7 +1484,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct exynos_dsi *dsi = connector_to_dsi(connector);
|
||||
|
||||
return dsi->encoder;
|
||||
return dsi->display.encoder;
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
|
||||
@ -1486,12 +1496,10 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
|
||||
static int exynos_dsi_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct exynos_dsi *dsi = display->ctx;
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
struct drm_connector *connector = &dsi->connector;
|
||||
int ret;
|
||||
|
||||
dsi->encoder = encoder;
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
ret = drm_connector_init(encoder->dev, connector,
|
||||
@ -1512,7 +1520,7 @@ static int exynos_dsi_create_connector(struct exynos_drm_display *display,
|
||||
static void exynos_dsi_mode_set(struct exynos_drm_display *display,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct exynos_dsi *dsi = display->ctx;
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
struct videomode *vm = &dsi->vm;
|
||||
|
||||
vm->hactive = mode->hdisplay;
|
||||
@ -1531,10 +1539,6 @@ static struct exynos_drm_display_ops exynos_dsi_display_ops = {
|
||||
.dpms = exynos_dsi_dpms
|
||||
};
|
||||
|
||||
static struct exynos_drm_display exynos_dsi_display = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_LCD,
|
||||
.ops = &exynos_dsi_display_ops,
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
|
||||
|
||||
/* of_* functions will be removed after merge of of_graph patches */
|
||||
@ -1640,28 +1644,28 @@ end:
|
||||
static int exynos_dsi_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct exynos_drm_display *display = dev_get_drvdata(dev);
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct exynos_dsi *dsi;
|
||||
int ret;
|
||||
|
||||
ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display);
|
||||
ret = exynos_drm_create_enc_conn(drm_dev, display);
|
||||
if (ret) {
|
||||
DRM_ERROR("Encoder create [%d] failed with %d\n",
|
||||
exynos_dsi_display.type, ret);
|
||||
display->type, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dsi = exynos_dsi_display.ctx;
|
||||
|
||||
return mipi_dsi_host_register(&dsi->dsi_host);
|
||||
}
|
||||
|
||||
static void exynos_dsi_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
|
||||
struct exynos_drm_display *display = dev_get_drvdata(dev);
|
||||
struct exynos_dsi *dsi = display_to_dsi(display);
|
||||
|
||||
exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
|
||||
exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
|
||||
|
||||
mipi_dsi_host_unregister(&dsi->dsi_host);
|
||||
}
|
||||
@ -1673,22 +1677,23 @@ static const struct component_ops exynos_dsi_component_ops = {
|
||||
|
||||
static int exynos_dsi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct exynos_dsi *dsi;
|
||||
int ret;
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
exynos_dsi_display.type);
|
||||
dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
|
||||
if (!dsi)
|
||||
return -ENOMEM;
|
||||
|
||||
dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
dsi->display.ops = &exynos_dsi_display_ops;
|
||||
|
||||
ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
dsi->display.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
|
||||
if (!dsi) {
|
||||
dev_err(&pdev->dev, "failed to allocate dsi object.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
/* To be checked as invalid one */
|
||||
dsi->te_gpio = -ENOENT;
|
||||
|
||||
@ -1697,9 +1702,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&dsi->transfer_list);
|
||||
|
||||
dsi->dsi_host.ops = &exynos_dsi_ops;
|
||||
dsi->dsi_host.dev = &pdev->dev;
|
||||
dsi->dsi_host.dev = dev;
|
||||
|
||||
dsi->dev = &pdev->dev;
|
||||
dsi->dev = dev;
|
||||
dsi->driver_data = exynos_dsi_get_driver_data(pdev);
|
||||
|
||||
ret = exynos_dsi_parse_dt(dsi);
|
||||
@ -1708,70 +1713,68 @@ static int exynos_dsi_probe(struct platform_device *pdev)
|
||||
|
||||
dsi->supplies[0].supply = "vddcore";
|
||||
dsi->supplies[1].supply = "vddio";
|
||||
ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies),
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies),
|
||||
dsi->supplies);
|
||||
if (ret) {
|
||||
dev_info(&pdev->dev, "failed to get regulators: %d\n", ret);
|
||||
dev_info(dev, "failed to get regulators: %d\n", ret);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk");
|
||||
dsi->pll_clk = devm_clk_get(dev, "pll_clk");
|
||||
if (IS_ERR(dsi->pll_clk)) {
|
||||
dev_info(&pdev->dev, "failed to get dsi pll input clock\n");
|
||||
dev_info(dev, "failed to get dsi pll input clock\n");
|
||||
ret = PTR_ERR(dsi->pll_clk);
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
|
||||
dsi->bus_clk = devm_clk_get(dev, "bus_clk");
|
||||
if (IS_ERR(dsi->bus_clk)) {
|
||||
dev_info(&pdev->dev, "failed to get dsi bus clock\n");
|
||||
dev_info(dev, "failed to get dsi bus clock\n");
|
||||
ret = PTR_ERR(dsi->bus_clk);
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
dsi->reg_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(dsi->reg_base)) {
|
||||
dev_err(&pdev->dev, "failed to remap io region\n");
|
||||
dev_err(dev, "failed to remap io region\n");
|
||||
ret = PTR_ERR(dsi->reg_base);
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
dsi->phy = devm_phy_get(&pdev->dev, "dsim");
|
||||
dsi->phy = devm_phy_get(dev, "dsim");
|
||||
if (IS_ERR(dsi->phy)) {
|
||||
dev_info(&pdev->dev, "failed to get dsim phy\n");
|
||||
dev_info(dev, "failed to get dsim phy\n");
|
||||
ret = PTR_ERR(dsi->phy);
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
dsi->irq = platform_get_irq(pdev, 0);
|
||||
if (dsi->irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to request dsi irq resource\n");
|
||||
dev_err(dev, "failed to request dsi irq resource\n");
|
||||
ret = dsi->irq;
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL,
|
||||
ret = devm_request_threaded_irq(dev, dsi->irq, NULL,
|
||||
exynos_dsi_irq, IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), dsi);
|
||||
dev_name(dev), dsi);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request dsi irq\n");
|
||||
dev_err(dev, "failed to request dsi irq\n");
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
exynos_dsi_display.ctx = dsi;
|
||||
platform_set_drvdata(pdev, &dsi->display);
|
||||
|
||||
platform_set_drvdata(pdev, &exynos_dsi_display);
|
||||
|
||||
ret = component_add(&pdev->dev, &exynos_dsi_component_ops);
|
||||
ret = component_add(dev, &exynos_dsi_component_ops);
|
||||
if (ret)
|
||||
goto err_del_component;
|
||||
|
||||
return ret;
|
||||
|
||||
err_del_component:
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,6 @@
|
||||
#ifndef _EXYNOS_DRM_ENCODER_H_
|
||||
#define _EXYNOS_DRM_ENCODER_H_
|
||||
|
||||
struct exynos_drm_manager;
|
||||
|
||||
void exynos_drm_encoder_setup(struct drm_device *dev);
|
||||
struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
|
||||
struct exynos_drm_display *mgr,
|
||||
|
@ -84,8 +84,6 @@
|
||||
/* FIMD has totally five hardware windows. */
|
||||
#define WINDOWS_NR 5
|
||||
|
||||
#define get_fimd_manager(mgr) platform_get_drvdata(to_platform_device(dev))
|
||||
|
||||
struct fimd_driver_data {
|
||||
unsigned int timing_base;
|
||||
unsigned int lcdblk_offset;
|
||||
@ -96,6 +94,7 @@ struct fimd_driver_data {
|
||||
unsigned int has_clksel:1;
|
||||
unsigned int has_limited_fmt:1;
|
||||
unsigned int has_vidoutcon:1;
|
||||
unsigned int has_vtsel:1;
|
||||
};
|
||||
|
||||
static struct fimd_driver_data s3c64xx_fimd_driver_data = {
|
||||
@ -118,6 +117,17 @@ static struct fimd_driver_data exynos4_fimd_driver_data = {
|
||||
.lcdblk_vt_shift = 10,
|
||||
.lcdblk_bypass_shift = 1,
|
||||
.has_shadowcon = 1,
|
||||
.has_vtsel = 1,
|
||||
};
|
||||
|
||||
static struct fimd_driver_data exynos4415_fimd_driver_data = {
|
||||
.timing_base = 0x20000,
|
||||
.lcdblk_offset = 0x210,
|
||||
.lcdblk_vt_shift = 10,
|
||||
.lcdblk_bypass_shift = 1,
|
||||
.has_shadowcon = 1,
|
||||
.has_vidoutcon = 1,
|
||||
.has_vtsel = 1,
|
||||
};
|
||||
|
||||
static struct fimd_driver_data exynos5_fimd_driver_data = {
|
||||
@ -127,6 +137,7 @@ static struct fimd_driver_data exynos5_fimd_driver_data = {
|
||||
.lcdblk_bypass_shift = 15,
|
||||
.has_shadowcon = 1,
|
||||
.has_vidoutcon = 1,
|
||||
.has_vtsel = 1,
|
||||
};
|
||||
|
||||
struct fimd_win_data {
|
||||
@ -146,6 +157,7 @@ struct fimd_win_data {
|
||||
};
|
||||
|
||||
struct fimd_context {
|
||||
struct exynos_drm_manager manager;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct clk *bus_clk;
|
||||
@ -173,6 +185,11 @@ struct fimd_context {
|
||||
struct exynos_drm_display *display;
|
||||
};
|
||||
|
||||
static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
return container_of(mgr, struct fimd_context, manager);
|
||||
}
|
||||
|
||||
static const struct of_device_id fimd_driver_dt_match[] = {
|
||||
{ .compatible = "samsung,s3c6400-fimd",
|
||||
.data = &s3c64xx_fimd_driver_data },
|
||||
@ -180,6 +197,8 @@ static const struct of_device_id fimd_driver_dt_match[] = {
|
||||
.data = &exynos3_fimd_driver_data },
|
||||
{ .compatible = "samsung,exynos4210-fimd",
|
||||
.data = &exynos4_fimd_driver_data },
|
||||
{ .compatible = "samsung,exynos4415-fimd",
|
||||
.data = &exynos4415_fimd_driver_data },
|
||||
{ .compatible = "samsung,exynos5250-fimd",
|
||||
.data = &exynos5_fimd_driver_data },
|
||||
{},
|
||||
@ -197,7 +216,7 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
|
||||
|
||||
static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
@ -214,9 +233,35 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
|
||||
DRM_DEBUG_KMS("vblank wait timed out.\n");
|
||||
}
|
||||
|
||||
static void fimd_enable_video_output(struct fimd_context *ctx, int win,
|
||||
bool enable)
|
||||
{
|
||||
u32 val = readl(ctx->regs + WINCON(win));
|
||||
|
||||
if (enable)
|
||||
val |= WINCONx_ENWIN;
|
||||
else
|
||||
val &= ~WINCONx_ENWIN;
|
||||
|
||||
writel(val, ctx->regs + WINCON(win));
|
||||
}
|
||||
|
||||
static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win,
|
||||
bool enable)
|
||||
{
|
||||
u32 val = readl(ctx->regs + SHADOWCON);
|
||||
|
||||
if (enable)
|
||||
val |= SHADOWCON_CHx_ENABLE(win);
|
||||
else
|
||||
val &= ~SHADOWCON_CHx_ENABLE(win);
|
||||
|
||||
writel(val, ctx->regs + SHADOWCON);
|
||||
}
|
||||
|
||||
static void fimd_clear_channel(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
int win, ch_enabled = 0;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
@ -226,16 +271,12 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
|
||||
u32 val = readl(ctx->regs + WINCON(win));
|
||||
|
||||
if (val & WINCONx_ENWIN) {
|
||||
/* wincon */
|
||||
val &= ~WINCONx_ENWIN;
|
||||
writel(val, ctx->regs + WINCON(win));
|
||||
fimd_enable_video_output(ctx, win, false);
|
||||
|
||||
if (ctx->driver_data->has_shadowcon)
|
||||
fimd_enable_shadow_channel_path(ctx, win,
|
||||
false);
|
||||
|
||||
/* unprotect windows */
|
||||
if (ctx->driver_data->has_shadowcon) {
|
||||
val = readl(ctx->regs + SHADOWCON);
|
||||
val &= ~SHADOWCON_CHx_ENABLE(win);
|
||||
writel(val, ctx->regs + SHADOWCON);
|
||||
}
|
||||
ch_enabled = 1;
|
||||
}
|
||||
}
|
||||
@ -253,7 +294,7 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
|
||||
static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
|
||||
struct drm_device *drm_dev)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct exynos_drm_private *priv;
|
||||
priv = drm_dev->dev_private;
|
||||
|
||||
@ -275,7 +316,7 @@ static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
|
||||
|
||||
static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
|
||||
/* detach this sub driver from iommu mapping if supported. */
|
||||
if (is_drm_iommu_supported(ctx->drm_dev))
|
||||
@ -315,14 +356,14 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
|
||||
static void fimd_mode_set(struct exynos_drm_manager *mgr,
|
||||
const struct drm_display_mode *in_mode)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
|
||||
drm_mode_copy(&ctx->mode, in_mode);
|
||||
}
|
||||
|
||||
static void fimd_commit(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct drm_display_mode *mode = &ctx->mode;
|
||||
struct fimd_driver_data *driver_data = ctx->driver_data;
|
||||
void *timing_base = ctx->regs + driver_data->timing_base;
|
||||
@ -343,7 +384,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
|
||||
writel(0, timing_base + I80IFCONFBx(0));
|
||||
|
||||
/* set video type selection to I80 interface */
|
||||
if (ctx->sysreg && regmap_update_bits(ctx->sysreg,
|
||||
if (driver_data->has_vtsel && ctx->sysreg &&
|
||||
regmap_update_bits(ctx->sysreg,
|
||||
driver_data->lcdblk_offset,
|
||||
0x3 << driver_data->lcdblk_vt_shift,
|
||||
0x1 << driver_data->lcdblk_vt_shift)) {
|
||||
@ -421,7 +463,7 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
|
||||
|
||||
static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
@ -431,12 +473,19 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
val = readl(ctx->regs + VIDINTCON0);
|
||||
|
||||
val |= VIDINTCON0_INT_ENABLE;
|
||||
val |= VIDINTCON0_INT_FRAME;
|
||||
|
||||
val &= ~VIDINTCON0_FRAMESEL0_MASK;
|
||||
val |= VIDINTCON0_FRAMESEL0_VSYNC;
|
||||
val &= ~VIDINTCON0_FRAMESEL1_MASK;
|
||||
val |= VIDINTCON0_FRAMESEL1_NONE;
|
||||
if (ctx->i80_if) {
|
||||
val |= VIDINTCON0_INT_I80IFDONE;
|
||||
val |= VIDINTCON0_INT_SYSMAINCON;
|
||||
val &= ~VIDINTCON0_INT_SYSSUBCON;
|
||||
} else {
|
||||
val |= VIDINTCON0_INT_FRAME;
|
||||
|
||||
val &= ~VIDINTCON0_FRAMESEL0_MASK;
|
||||
val |= VIDINTCON0_FRAMESEL0_VSYNC;
|
||||
val &= ~VIDINTCON0_FRAMESEL1_MASK;
|
||||
val |= VIDINTCON0_FRAMESEL1_NONE;
|
||||
}
|
||||
|
||||
writel(val, ctx->regs + VIDINTCON0);
|
||||
}
|
||||
@ -446,7 +495,7 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
u32 val;
|
||||
|
||||
if (ctx->suspended)
|
||||
@ -455,9 +504,15 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
if (test_and_clear_bit(0, &ctx->irq_flags)) {
|
||||
val = readl(ctx->regs + VIDINTCON0);
|
||||
|
||||
val &= ~VIDINTCON0_INT_FRAME;
|
||||
val &= ~VIDINTCON0_INT_ENABLE;
|
||||
|
||||
if (ctx->i80_if) {
|
||||
val &= ~VIDINTCON0_INT_I80IFDONE;
|
||||
val &= ~VIDINTCON0_INT_SYSMAINCON;
|
||||
val &= ~VIDINTCON0_INT_SYSSUBCON;
|
||||
} else
|
||||
val &= ~VIDINTCON0_INT_FRAME;
|
||||
|
||||
writel(val, ctx->regs + VIDINTCON0);
|
||||
}
|
||||
}
|
||||
@ -465,7 +520,7 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
|
||||
struct exynos_drm_overlay *overlay)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct fimd_win_data *win_data;
|
||||
int win;
|
||||
unsigned long offset;
|
||||
@ -623,7 +678,7 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
|
||||
|
||||
static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct fimd_win_data *win_data;
|
||||
int win = zpos;
|
||||
unsigned long val, alpha, size;
|
||||
@ -730,20 +785,14 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
if (win != 0)
|
||||
fimd_win_set_colkey(ctx, win);
|
||||
|
||||
/* wincon */
|
||||
val = readl(ctx->regs + WINCON(win));
|
||||
val |= WINCONx_ENWIN;
|
||||
writel(val, ctx->regs + WINCON(win));
|
||||
fimd_enable_video_output(ctx, win, true);
|
||||
|
||||
if (ctx->driver_data->has_shadowcon)
|
||||
fimd_enable_shadow_channel_path(ctx, win, true);
|
||||
|
||||
/* Enable DMA channel and unprotect windows */
|
||||
fimd_shadow_protect_win(ctx, win, false);
|
||||
|
||||
if (ctx->driver_data->has_shadowcon) {
|
||||
val = readl(ctx->regs + SHADOWCON);
|
||||
val |= SHADOWCON_CHx_ENABLE(win);
|
||||
writel(val, ctx->regs + SHADOWCON);
|
||||
}
|
||||
|
||||
win_data->enabled = true;
|
||||
|
||||
if (ctx->i80_if)
|
||||
@ -752,10 +801,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
|
||||
static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct fimd_win_data *win_data;
|
||||
int win = zpos;
|
||||
u32 val;
|
||||
|
||||
if (win == DEFAULT_ZPOS)
|
||||
win = ctx->default_win;
|
||||
@ -774,18 +822,12 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
/* protect windows */
|
||||
fimd_shadow_protect_win(ctx, win, true);
|
||||
|
||||
/* wincon */
|
||||
val = readl(ctx->regs + WINCON(win));
|
||||
val &= ~WINCONx_ENWIN;
|
||||
writel(val, ctx->regs + WINCON(win));
|
||||
fimd_enable_video_output(ctx, win, false);
|
||||
|
||||
if (ctx->driver_data->has_shadowcon)
|
||||
fimd_enable_shadow_channel_path(ctx, win, false);
|
||||
|
||||
/* unprotect windows */
|
||||
if (ctx->driver_data->has_shadowcon) {
|
||||
val = readl(ctx->regs + SHADOWCON);
|
||||
val &= ~SHADOWCON_CHx_ENABLE(win);
|
||||
writel(val, ctx->regs + SHADOWCON);
|
||||
}
|
||||
|
||||
fimd_shadow_protect_win(ctx, win, false);
|
||||
|
||||
win_data->enabled = false;
|
||||
@ -793,7 +835,7 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
|
||||
static void fimd_window_suspend(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct fimd_win_data *win_data;
|
||||
int i;
|
||||
|
||||
@ -803,12 +845,11 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr)
|
||||
if (win_data->enabled)
|
||||
fimd_win_disable(mgr, i);
|
||||
}
|
||||
fimd_wait_for_vblank(mgr);
|
||||
}
|
||||
|
||||
static void fimd_window_resume(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct fimd_win_data *win_data;
|
||||
int i;
|
||||
|
||||
@ -821,7 +862,7 @@ static void fimd_window_resume(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void fimd_apply(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
struct fimd_win_data *win_data;
|
||||
int i;
|
||||
|
||||
@ -838,7 +879,7 @@ static void fimd_apply(struct exynos_drm_manager *mgr)
|
||||
|
||||
static int fimd_poweron(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
int ret;
|
||||
|
||||
if (!ctx->suspended)
|
||||
@ -886,7 +927,7 @@ bus_clk_err:
|
||||
|
||||
static int fimd_poweroff(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
|
||||
if (ctx->suspended)
|
||||
return 0;
|
||||
@ -928,39 +969,41 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
|
||||
|
||||
static void fimd_trigger(struct device *dev)
|
||||
{
|
||||
struct exynos_drm_manager *mgr = get_fimd_manager(dev);
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = dev_get_drvdata(dev);
|
||||
struct fimd_driver_data *driver_data = ctx->driver_data;
|
||||
void *timing_base = ctx->regs + driver_data->timing_base;
|
||||
u32 reg;
|
||||
|
||||
atomic_set(&ctx->triggering, 1);
|
||||
/*
|
||||
* Skips triggering if in triggering state, because multiple triggering
|
||||
* requests can cause panel reset.
|
||||
*/
|
||||
if (atomic_read(&ctx->triggering))
|
||||
return;
|
||||
|
||||
reg = readl(ctx->regs + VIDINTCON0);
|
||||
reg |= (VIDINTCON0_INT_ENABLE | VIDINTCON0_INT_I80IFDONE |
|
||||
VIDINTCON0_INT_SYSMAINCON);
|
||||
writel(reg, ctx->regs + VIDINTCON0);
|
||||
/* Enters triggering mode */
|
||||
atomic_set(&ctx->triggering, 1);
|
||||
|
||||
reg = readl(timing_base + TRIGCON);
|
||||
reg |= (TRGMODE_I80_RGB_ENABLE_I80 | SWTRGCMD_I80_RGB_ENABLE);
|
||||
writel(reg, timing_base + TRIGCON);
|
||||
|
||||
/*
|
||||
* Exits triggering mode if vblank is not enabled yet, because when the
|
||||
* VIDINTCON0 register is not set, it can not exit from triggering mode.
|
||||
*/
|
||||
if (!test_bit(0, &ctx->irq_flags))
|
||||
atomic_set(&ctx->triggering, 0);
|
||||
}
|
||||
|
||||
static void fimd_te_handler(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct fimd_context *ctx = mgr->ctx;
|
||||
struct fimd_context *ctx = mgr_to_fimd(mgr);
|
||||
|
||||
/* Checks the crtc is detached already from encoder */
|
||||
if (ctx->pipe < 0 || !ctx->drm_dev)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Skips to trigger if in triggering state, because multiple triggering
|
||||
* requests can cause panel reset.
|
||||
*/
|
||||
if (atomic_read(&ctx->triggering))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If there is a page flip request, triggers and handles the page flip
|
||||
* event so that current fb can be updated into panel GRAM.
|
||||
@ -972,10 +1015,10 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr)
|
||||
if (atomic_read(&ctx->wait_vsync_event)) {
|
||||
atomic_set(&ctx->wait_vsync_event, 0);
|
||||
wake_up(&ctx->wait_vsync_queue);
|
||||
|
||||
if (!atomic_read(&ctx->triggering))
|
||||
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
|
||||
}
|
||||
|
||||
if (test_bit(0, &ctx->irq_flags))
|
||||
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
|
||||
}
|
||||
|
||||
static struct exynos_drm_manager_ops fimd_manager_ops = {
|
||||
@ -992,11 +1035,6 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
|
||||
.te_handler = fimd_te_handler,
|
||||
};
|
||||
|
||||
static struct exynos_drm_manager fimd_manager = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_LCD,
|
||||
.ops = &fimd_manager_ops,
|
||||
};
|
||||
|
||||
static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct fimd_context *ctx = (struct fimd_context *)dev_id;
|
||||
@ -1013,16 +1051,10 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
|
||||
goto out;
|
||||
|
||||
if (ctx->i80_if) {
|
||||
/* unset I80 frame done interrupt */
|
||||
val = readl(ctx->regs + VIDINTCON0);
|
||||
val &= ~(VIDINTCON0_INT_I80IFDONE | VIDINTCON0_INT_SYSMAINCON);
|
||||
writel(val, ctx->regs + VIDINTCON0);
|
||||
|
||||
/* exit triggering mode */
|
||||
atomic_set(&ctx->triggering, 0);
|
||||
|
||||
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
|
||||
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
|
||||
|
||||
/* Exits triggering mode */
|
||||
atomic_set(&ctx->triggering, 0);
|
||||
} else {
|
||||
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
|
||||
exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
|
||||
@ -1040,11 +1072,11 @@ out:
|
||||
|
||||
static int fimd_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct fimd_context *ctx = fimd_manager.ctx;
|
||||
struct fimd_context *ctx = dev_get_drvdata(dev);
|
||||
struct drm_device *drm_dev = data;
|
||||
|
||||
fimd_mgr_initialize(&fimd_manager, drm_dev);
|
||||
exynos_drm_crtc_create(&fimd_manager);
|
||||
fimd_mgr_initialize(&ctx->manager, drm_dev);
|
||||
exynos_drm_crtc_create(&ctx->manager);
|
||||
if (ctx->display)
|
||||
exynos_drm_create_enc_conn(drm_dev, ctx->display);
|
||||
|
||||
@ -1055,15 +1087,14 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
|
||||
static void fimd_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
|
||||
struct fimd_context *ctx = fimd_manager.ctx;
|
||||
struct fimd_context *ctx = dev_get_drvdata(dev);
|
||||
|
||||
fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
|
||||
fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF);
|
||||
|
||||
if (ctx->display)
|
||||
exynos_dpi_remove(dev);
|
||||
exynos_dpi_remove(ctx->display);
|
||||
|
||||
fimd_mgr_remove(mgr);
|
||||
fimd_mgr_remove(&ctx->manager);
|
||||
}
|
||||
|
||||
static const struct component_ops fimd_component_ops = {
|
||||
@ -1079,21 +1110,20 @@ static int fimd_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int ret = -EINVAL;
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
|
||||
fimd_manager.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dev->of_node) {
|
||||
ret = -ENODEV;
|
||||
goto err_del_component;
|
||||
}
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx) {
|
||||
ret = -ENOMEM;
|
||||
goto err_del_component;
|
||||
}
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->manager.type = EXYNOS_DISPLAY_TYPE_LCD;
|
||||
ctx->manager.ops = &fimd_manager_ops;
|
||||
|
||||
ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
|
||||
ctx->manager.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->dev = dev;
|
||||
ctx->suspended = true;
|
||||
@ -1182,27 +1212,27 @@ static int fimd_probe(struct platform_device *pdev)
|
||||
init_waitqueue_head(&ctx->wait_vsync_queue);
|
||||
atomic_set(&ctx->wait_vsync_event, 0);
|
||||
|
||||
platform_set_drvdata(pdev, &fimd_manager);
|
||||
|
||||
fimd_manager.ctx = ctx;
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ctx->display = exynos_dpi_probe(dev);
|
||||
if (IS_ERR(ctx->display))
|
||||
return PTR_ERR(ctx->display);
|
||||
if (IS_ERR(ctx->display)) {
|
||||
ret = PTR_ERR(ctx->display);
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = component_add(&pdev->dev, &fimd_component_ops);
|
||||
ret = component_add(dev, &fimd_component_ops);
|
||||
if (ret)
|
||||
goto err_disable_pm_runtime;
|
||||
|
||||
return ret;
|
||||
|
||||
err_disable_pm_runtime:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
err_del_component:
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
|
||||
exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -302,9 +302,12 @@ static void g2d_fini_cmdlist(struct g2d_data *g2d)
|
||||
struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
|
||||
|
||||
kfree(g2d->cmdlist_node);
|
||||
dma_free_attrs(subdrv->drm_dev->dev, G2D_CMDLIST_POOL_SIZE,
|
||||
g2d->cmdlist_pool_virt,
|
||||
g2d->cmdlist_pool, &g2d->cmdlist_dma_attrs);
|
||||
|
||||
if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) {
|
||||
dma_free_attrs(subdrv->drm_dev->dev, G2D_CMDLIST_POOL_SIZE,
|
||||
g2d->cmdlist_pool_virt,
|
||||
g2d->cmdlist_pool, &g2d->cmdlist_dma_attrs);
|
||||
}
|
||||
}
|
||||
|
||||
static struct g2d_cmdlist_node *g2d_get_cmdlist(struct g2d_data *g2d)
|
||||
|
@ -40,7 +40,6 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
|
||||
|
||||
#else
|
||||
|
||||
struct dma_iommu_mapping;
|
||||
static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
|
||||
{
|
||||
return 0;
|
||||
|
@ -426,18 +426,21 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
|
||||
c_node->start_work = ipp_create_cmd_work();
|
||||
if (IS_ERR(c_node->start_work)) {
|
||||
DRM_ERROR("failed to create start work.\n");
|
||||
ret = PTR_ERR(c_node->start_work);
|
||||
goto err_remove_id;
|
||||
}
|
||||
|
||||
c_node->stop_work = ipp_create_cmd_work();
|
||||
if (IS_ERR(c_node->stop_work)) {
|
||||
DRM_ERROR("failed to create stop work.\n");
|
||||
ret = PTR_ERR(c_node->stop_work);
|
||||
goto err_free_start;
|
||||
}
|
||||
|
||||
c_node->event_work = ipp_create_event_work();
|
||||
if (IS_ERR(c_node->event_work)) {
|
||||
DRM_ERROR("failed to create event work.\n");
|
||||
ret = PTR_ERR(c_node->event_work);
|
||||
goto err_free_stop;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/component.h>
|
||||
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
@ -28,7 +29,6 @@
|
||||
/* vidi has totally three virtual windows. */
|
||||
#define WINDOWS_NR 3
|
||||
|
||||
#define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
#define ctx_from_connector(c) container_of(c, struct vidi_context, \
|
||||
connector)
|
||||
|
||||
@ -47,11 +47,13 @@ struct vidi_win_data {
|
||||
};
|
||||
|
||||
struct vidi_context {
|
||||
struct exynos_drm_manager manager;
|
||||
struct exynos_drm_display display;
|
||||
struct platform_device *pdev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector connector;
|
||||
struct exynos_drm_subdrv subdrv;
|
||||
struct vidi_win_data win_data[WINDOWS_NR];
|
||||
struct edid *raw_edid;
|
||||
unsigned int clkdiv;
|
||||
@ -66,6 +68,16 @@ struct vidi_context {
|
||||
int pipe;
|
||||
};
|
||||
|
||||
static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
|
||||
{
|
||||
return container_of(m, struct vidi_context, manager);
|
||||
}
|
||||
|
||||
static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
|
||||
{
|
||||
return container_of(d, struct vidi_context, display);
|
||||
}
|
||||
|
||||
static const char fake_edid_info[] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
|
||||
0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
|
||||
@ -93,7 +105,7 @@ static const char fake_edid_info[] = {
|
||||
|
||||
static void vidi_apply(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
|
||||
struct vidi_win_data *win_data;
|
||||
int i;
|
||||
@ -110,7 +122,7 @@ static void vidi_apply(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void vidi_commit(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
@ -118,7 +130,7 @@ static void vidi_commit(struct exynos_drm_manager *mgr)
|
||||
|
||||
static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
|
||||
if (ctx->suspended)
|
||||
return -EPERM;
|
||||
@ -140,7 +152,7 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
|
||||
if (ctx->suspended)
|
||||
return;
|
||||
@ -152,7 +164,7 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
|
||||
struct exynos_drm_overlay *overlay)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
struct vidi_win_data *win_data;
|
||||
int win;
|
||||
unsigned long offset;
|
||||
@ -204,7 +216,7 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
|
||||
|
||||
static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
struct vidi_win_data *win_data;
|
||||
int win = zpos;
|
||||
|
||||
@ -229,7 +241,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
|
||||
static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
struct vidi_win_data *win_data;
|
||||
int win = zpos;
|
||||
|
||||
@ -247,7 +259,7 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
|
||||
static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
@ -271,7 +283,7 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
|
||||
|
||||
static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
|
||||
DRM_DEBUG_KMS("%d\n", mode);
|
||||
|
||||
@ -297,7 +309,7 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
|
||||
static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
|
||||
struct drm_device *drm_dev)
|
||||
{
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = manager_to_vidi(mgr);
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
|
||||
mgr->drm_dev = ctx->drm_dev = drm_dev;
|
||||
@ -316,11 +328,6 @@ static struct exynos_drm_manager_ops vidi_manager_ops = {
|
||||
.win_disable = vidi_win_disable,
|
||||
};
|
||||
|
||||
static struct exynos_drm_manager vidi_manager = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_VIDI,
|
||||
.ops = &vidi_manager_ops,
|
||||
};
|
||||
|
||||
static void vidi_fake_vblank_handler(struct work_struct *work)
|
||||
{
|
||||
struct vidi_context *ctx = container_of(work, struct vidi_context,
|
||||
@ -349,9 +356,8 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
|
||||
static int vidi_show_connection(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct vidi_context *ctx = dev_get_drvdata(dev);
|
||||
int rc;
|
||||
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
@ -366,8 +372,7 @@ static int vidi_store_connection(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = kstrtoint(buf, 0, &ctx->connected);
|
||||
@ -420,7 +425,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
|
||||
display = exynos_drm_get_display(encoder);
|
||||
|
||||
if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
|
||||
ctx = display->ctx;
|
||||
ctx = display_to_vidi(display);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -530,7 +535,7 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
|
||||
static int vidi_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct vidi_context *ctx = display->ctx;
|
||||
struct vidi_context *ctx = display_to_vidi(display);
|
||||
struct drm_connector *connector = &ctx->connector;
|
||||
int ret;
|
||||
|
||||
@ -556,27 +561,22 @@ static struct exynos_drm_display_ops vidi_display_ops = {
|
||||
.create_connector = vidi_create_connector,
|
||||
};
|
||||
|
||||
static struct exynos_drm_display vidi_display = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_VIDI,
|
||||
.ops = &vidi_display_ops,
|
||||
};
|
||||
|
||||
static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
|
||||
static int vidi_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = dev_get_drvdata(dev);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct drm_crtc *crtc = ctx->crtc;
|
||||
int ret;
|
||||
|
||||
vidi_mgr_initialize(mgr, drm_dev);
|
||||
vidi_mgr_initialize(&ctx->manager, drm_dev);
|
||||
|
||||
ret = exynos_drm_crtc_create(&vidi_manager);
|
||||
ret = exynos_drm_crtc_create(&ctx->manager);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to create crtc.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display);
|
||||
ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
|
||||
if (ret) {
|
||||
crtc->funcs->destroy(crtc);
|
||||
DRM_ERROR("failed to create encoder and connector.\n");
|
||||
@ -586,9 +586,18 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void vidi_unbind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct component_ops vidi_component_ops = {
|
||||
.bind = vidi_bind,
|
||||
.unbind = vidi_unbind,
|
||||
};
|
||||
|
||||
static int vidi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_drm_subdrv *subdrv;
|
||||
struct vidi_context *ctx;
|
||||
int ret;
|
||||
|
||||
@ -596,40 +605,54 @@ static int vidi_probe(struct platform_device *pdev)
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
|
||||
ctx->manager.ops = &vidi_manager_ops;
|
||||
ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
|
||||
ctx->display.ops = &vidi_display_ops;
|
||||
ctx->default_win = 0;
|
||||
ctx->pdev = pdev;
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
|
||||
ctx->manager.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
ctx->display.type);
|
||||
if (ret)
|
||||
goto err_del_crtc_component;
|
||||
|
||||
INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
|
||||
|
||||
vidi_manager.ctx = ctx;
|
||||
vidi_display.ctx = ctx;
|
||||
|
||||
mutex_init(&ctx->lock);
|
||||
|
||||
platform_set_drvdata(pdev, &vidi_manager);
|
||||
|
||||
subdrv = &ctx->subdrv;
|
||||
subdrv->dev = &pdev->dev;
|
||||
subdrv->probe = vidi_subdrv_probe;
|
||||
|
||||
ret = exynos_drm_subdrv_register(subdrv);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to register drm vidi device\n");
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = device_create_file(&pdev->dev, &dev_attr_connection);
|
||||
if (ret < 0) {
|
||||
exynos_drm_subdrv_unregister(subdrv);
|
||||
DRM_INFO("failed to create connection sysfs.\n");
|
||||
DRM_ERROR("failed to create connection sysfs.\n");
|
||||
goto err_del_conn_component;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = component_add(&pdev->dev, &vidi_component_ops);
|
||||
if (ret)
|
||||
goto err_remove_file;
|
||||
|
||||
return ret;
|
||||
|
||||
err_remove_file:
|
||||
device_remove_file(&pdev->dev, &dev_attr_connection);
|
||||
err_del_conn_component:
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
err_del_crtc_component:
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vidi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
|
||||
struct vidi_context *ctx = mgr->ctx;
|
||||
struct vidi_context *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
|
||||
kfree(ctx->raw_edid);
|
||||
@ -638,6 +661,10 @@ static int vidi_remove(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
component_del(&pdev->dev, &vidi_component_ops);
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -668,12 +695,19 @@ int exynos_drm_probe_vidi(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_drm_remove_vidi_device(struct device *dev, void *data)
|
||||
{
|
||||
platform_device_unregister(to_platform_device(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_drm_remove_vidi(void)
|
||||
{
|
||||
struct vidi_context *ctx = vidi_manager.ctx;
|
||||
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
|
||||
struct platform_device *pdev = to_platform_device(subdrv->dev);
|
||||
int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
|
||||
exynos_drm_remove_vidi_device);
|
||||
/* silence compiler warning */
|
||||
(void)ret;
|
||||
|
||||
platform_driver_unregister(&vidi_driver);
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
|
@ -49,7 +49,6 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <media/s5p_hdmi.h>
|
||||
|
||||
#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
|
||||
|
||||
#define HOTPLUG_DEBOUNCE_MS 1100
|
||||
@ -182,6 +181,7 @@ struct hdmi_conf_regs {
|
||||
};
|
||||
|
||||
struct hdmi_context {
|
||||
struct exynos_drm_display display;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector connector;
|
||||
@ -213,6 +213,11 @@ struct hdmi_context {
|
||||
enum hdmi_type type;
|
||||
};
|
||||
|
||||
static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
|
||||
{
|
||||
return container_of(d, struct hdmi_context, display);
|
||||
}
|
||||
|
||||
struct hdmiphy_config {
|
||||
int pixel_clock;
|
||||
u8 conf[32];
|
||||
@ -1123,7 +1128,7 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
|
||||
static int hdmi_create_connector(struct exynos_drm_display *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct hdmi_context *hdata = display->ctx;
|
||||
struct hdmi_context *hdata = display_to_hdmi(display);
|
||||
struct drm_connector *connector = &hdata->connector;
|
||||
int ret;
|
||||
|
||||
@ -2000,7 +2005,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
|
||||
static void hdmi_mode_set(struct exynos_drm_display *display,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct hdmi_context *hdata = display->ctx;
|
||||
struct hdmi_context *hdata = display_to_hdmi(display);
|
||||
struct drm_display_mode *m = mode;
|
||||
|
||||
DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
|
||||
@ -2019,7 +2024,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display,
|
||||
|
||||
static void hdmi_commit(struct exynos_drm_display *display)
|
||||
{
|
||||
struct hdmi_context *hdata = display->ctx;
|
||||
struct hdmi_context *hdata = display_to_hdmi(display);
|
||||
|
||||
mutex_lock(&hdata->hdmi_mutex);
|
||||
if (!hdata->powered) {
|
||||
@ -2033,7 +2038,7 @@ static void hdmi_commit(struct exynos_drm_display *display)
|
||||
|
||||
static void hdmi_poweron(struct exynos_drm_display *display)
|
||||
{
|
||||
struct hdmi_context *hdata = display->ctx;
|
||||
struct hdmi_context *hdata = display_to_hdmi(display);
|
||||
struct hdmi_resources *res = &hdata->res;
|
||||
|
||||
mutex_lock(&hdata->hdmi_mutex);
|
||||
@ -2064,7 +2069,7 @@ static void hdmi_poweron(struct exynos_drm_display *display)
|
||||
|
||||
static void hdmi_poweroff(struct exynos_drm_display *display)
|
||||
{
|
||||
struct hdmi_context *hdata = display->ctx;
|
||||
struct hdmi_context *hdata = display_to_hdmi(display);
|
||||
struct hdmi_resources *res = &hdata->res;
|
||||
|
||||
mutex_lock(&hdata->hdmi_mutex);
|
||||
@ -2099,7 +2104,7 @@ out:
|
||||
|
||||
static void hdmi_dpms(struct exynos_drm_display *display, int mode)
|
||||
{
|
||||
struct hdmi_context *hdata = display->ctx;
|
||||
struct hdmi_context *hdata = display_to_hdmi(display);
|
||||
struct drm_encoder *encoder = hdata->encoder;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct drm_crtc_helper_funcs *funcs = NULL;
|
||||
@ -2143,11 +2148,6 @@ static struct exynos_drm_display_ops hdmi_display_ops = {
|
||||
.commit = hdmi_commit,
|
||||
};
|
||||
|
||||
static struct exynos_drm_display hdmi_display = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_HDMI,
|
||||
.ops = &hdmi_display_ops,
|
||||
};
|
||||
|
||||
static void hdmi_hotplug_work_func(struct work_struct *work)
|
||||
{
|
||||
struct hdmi_context *hdata;
|
||||
@ -2302,12 +2302,11 @@ MODULE_DEVICE_TABLE (of, hdmi_match_types);
|
||||
static int hdmi_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct drm_device *drm_dev = data;
|
||||
struct hdmi_context *hdata;
|
||||
struct hdmi_context *hdata = dev_get_drvdata(dev);
|
||||
|
||||
hdata = hdmi_display.ctx;
|
||||
hdata->drm_dev = drm_dev;
|
||||
|
||||
return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
|
||||
return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
|
||||
}
|
||||
|
||||
static void hdmi_unbind(struct device *dev, struct device *master, void *data)
|
||||
@ -2349,31 +2348,28 @@ static int hdmi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
pdata = drm_hdmi_dt_parse_pdata(dev);
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
|
||||
if (!hdata)
|
||||
return -ENOMEM;
|
||||
|
||||
hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
|
||||
hdata->display.ops = &hdmi_display_ops;
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
|
||||
hdmi_display.type);
|
||||
hdata->display.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dev->of_node) {
|
||||
ret = -ENODEV;
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
pdata = drm_hdmi_dt_parse_pdata(dev);
|
||||
if (!pdata) {
|
||||
ret = -EINVAL;
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
|
||||
if (!hdata) {
|
||||
ret = -ENOMEM;
|
||||
goto err_del_component;
|
||||
}
|
||||
|
||||
mutex_init(&hdata->hdmi_mutex);
|
||||
|
||||
platform_set_drvdata(pdev, &hdmi_display);
|
||||
platform_set_drvdata(pdev, hdata);
|
||||
|
||||
match = of_match_node(hdmi_match_types, dev->of_node);
|
||||
if (!match) {
|
||||
@ -2485,7 +2481,6 @@ out_get_phy_port:
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
hdmi_display.ctx = hdata;
|
||||
|
||||
ret = component_add(&pdev->dev, &hdmi_component_ops);
|
||||
if (ret)
|
||||
@ -2510,7 +2505,7 @@ err_del_component:
|
||||
|
||||
static int hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hdmi_context *hdata = hdmi_display.ctx;
|
||||
struct hdmi_context *hdata = platform_get_drvdata(pdev);
|
||||
|
||||
cancel_delayed_work_sync(&hdata->hotplug_work);
|
||||
|
||||
|
@ -40,8 +40,6 @@
|
||||
#include "exynos_drm_iommu.h"
|
||||
#include "exynos_mixer.h"
|
||||
|
||||
#define get_mixer_manager(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
|
||||
#define MIXER_WIN_NR 3
|
||||
#define MIXER_DEFAULT_WIN 0
|
||||
|
||||
@ -86,6 +84,7 @@ enum mixer_version_id {
|
||||
};
|
||||
|
||||
struct mixer_context {
|
||||
struct exynos_drm_manager manager;
|
||||
struct platform_device *pdev;
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
@ -104,6 +103,11 @@ struct mixer_context {
|
||||
atomic_t wait_vsync_event;
|
||||
};
|
||||
|
||||
static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
return container_of(mgr, struct mixer_context, manager);
|
||||
}
|
||||
|
||||
struct mixer_drv_data {
|
||||
enum mixer_version_id version;
|
||||
bool is_vp_enabled;
|
||||
@ -854,7 +858,7 @@ static int mixer_initialize(struct exynos_drm_manager *mgr,
|
||||
struct drm_device *drm_dev)
|
||||
{
|
||||
int ret;
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
struct exynos_drm_private *priv;
|
||||
priv = drm_dev->dev_private;
|
||||
|
||||
@ -885,7 +889,7 @@ static int mixer_initialize(struct exynos_drm_manager *mgr,
|
||||
|
||||
static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
|
||||
if (is_drm_iommu_supported(mixer_ctx->drm_dev))
|
||||
drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
|
||||
@ -893,7 +897,7 @@ static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
|
||||
|
||||
static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
struct mixer_resources *res = &mixer_ctx->mixer_res;
|
||||
|
||||
if (!mixer_ctx->powered) {
|
||||
@ -910,7 +914,7 @@ static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
struct mixer_resources *res = &mixer_ctx->mixer_res;
|
||||
|
||||
/* disable vsync interrupt */
|
||||
@ -920,7 +924,7 @@ static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
|
||||
static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
|
||||
struct exynos_drm_overlay *overlay)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
struct hdmi_win_data *win_data;
|
||||
int win;
|
||||
|
||||
@ -971,7 +975,7 @@ static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
|
||||
|
||||
static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
|
||||
|
||||
DRM_DEBUG_KMS("win: %d\n", win);
|
||||
@ -993,7 +997,7 @@ static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
|
||||
|
||||
static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
struct mixer_resources *res = &mixer_ctx->mixer_res;
|
||||
int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
|
||||
unsigned long flags;
|
||||
@ -1021,7 +1025,7 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
|
||||
|
||||
static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = mgr->ctx;
|
||||
struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
|
||||
|
||||
mutex_lock(&mixer_ctx->mixer_mutex);
|
||||
if (!mixer_ctx->powered) {
|
||||
@ -1048,7 +1052,7 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void mixer_window_suspend(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *ctx = mgr->ctx;
|
||||
struct mixer_context *ctx = mgr_to_mixer(mgr);
|
||||
struct hdmi_win_data *win_data;
|
||||
int i;
|
||||
|
||||
@ -1062,7 +1066,7 @@ static void mixer_window_suspend(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void mixer_window_resume(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *ctx = mgr->ctx;
|
||||
struct mixer_context *ctx = mgr_to_mixer(mgr);
|
||||
struct hdmi_win_data *win_data;
|
||||
int i;
|
||||
|
||||
@ -1077,7 +1081,7 @@ static void mixer_window_resume(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void mixer_poweron(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *ctx = mgr->ctx;
|
||||
struct mixer_context *ctx = mgr_to_mixer(mgr);
|
||||
struct mixer_resources *res = &ctx->mixer_res;
|
||||
|
||||
mutex_lock(&ctx->mixer_mutex);
|
||||
@ -1111,7 +1115,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
|
||||
|
||||
static void mixer_poweroff(struct exynos_drm_manager *mgr)
|
||||
{
|
||||
struct mixer_context *ctx = mgr->ctx;
|
||||
struct mixer_context *ctx = mgr_to_mixer(mgr);
|
||||
struct mixer_resources *res = &ctx->mixer_res;
|
||||
|
||||
mutex_lock(&ctx->mixer_mutex);
|
||||
@ -1187,11 +1191,6 @@ static struct exynos_drm_manager_ops mixer_manager_ops = {
|
||||
.win_disable = mixer_win_disable,
|
||||
};
|
||||
|
||||
static struct exynos_drm_manager mixer_manager = {
|
||||
.type = EXYNOS_DISPLAY_TYPE_HDMI,
|
||||
.ops = &mixer_manager_ops,
|
||||
};
|
||||
|
||||
static struct mixer_drv_data exynos5420_mxr_drv_data = {
|
||||
.version = MXR_VER_128_0_0_184,
|
||||
.is_vp_enabled = 0,
|
||||
@ -1249,13 +1248,45 @@ MODULE_DEVICE_TABLE(of, mixer_match_types);
|
||||
|
||||
static int mixer_bind(struct device *dev, struct device *manager, void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct mixer_context *ctx = dev_get_drvdata(dev);
|
||||
struct drm_device *drm_dev = data;
|
||||
struct mixer_context *ctx;
|
||||
struct mixer_drv_data *drv;
|
||||
int ret;
|
||||
|
||||
dev_info(dev, "probe start\n");
|
||||
ret = mixer_initialize(&ctx->manager, drm_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = exynos_drm_crtc_create(&ctx->manager);
|
||||
if (ret) {
|
||||
mixer_mgr_remove(&ctx->manager);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mixer_unbind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct mixer_context *ctx = dev_get_drvdata(dev);
|
||||
|
||||
mixer_mgr_remove(&ctx->manager);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
static const struct component_ops mixer_component_ops = {
|
||||
.bind = mixer_bind,
|
||||
.unbind = mixer_unbind,
|
||||
};
|
||||
|
||||
static int mixer_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mixer_drv_data *drv;
|
||||
struct mixer_context *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx) {
|
||||
@ -1265,8 +1296,12 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
|
||||
|
||||
mutex_init(&ctx->mixer_mutex);
|
||||
|
||||
ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI;
|
||||
ctx->manager.ops = &mixer_manager_ops;
|
||||
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(mixer_match_types, dev->of_node);
|
||||
drv = (struct mixer_drv_data *)match->data;
|
||||
} else {
|
||||
@ -1282,57 +1317,28 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
|
||||
init_waitqueue_head(&ctx->wait_vsync_queue);
|
||||
atomic_set(&ctx->wait_vsync_event, 0);
|
||||
|
||||
mixer_manager.ctx = ctx;
|
||||
ret = mixer_initialize(&mixer_manager, drm_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, &mixer_manager);
|
||||
ret = exynos_drm_crtc_create(&mixer_manager);
|
||||
if (ret) {
|
||||
mixer_mgr_remove(&mixer_manager);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mixer_unbind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
|
||||
|
||||
dev_info(dev, "remove successful\n");
|
||||
|
||||
mixer_mgr_remove(mgr);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
static const struct component_ops mixer_component_ops = {
|
||||
.bind = mixer_bind,
|
||||
.unbind = mixer_unbind,
|
||||
};
|
||||
|
||||
static int mixer_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
|
||||
mixer_manager.type);
|
||||
ctx->manager.type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = component_add(&pdev->dev, &mixer_component_ops);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mixer_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
component_del(&pdev->dev, &mixer_component_ops);
|
||||
exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user