Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This is final pull request for Exynos next and includes device tree support for fimc device, one revert, some code cleanups and fixup. The revert replaces wrong one[1] with correct one[2]. This was my mistake and sorry for this. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos: Don't blend mixer layer 0 drm/exynos: Remove unnecessary braces in exynos_hdmi.c drm/exynos: Select VIDEOMODE_HELPERS for FIMD drm/exynos: do not use generic flags to dumb drm/exynos: added ipp device registration to drm driver exynos/drm: hdmi: cleanup for hdmi common device registration drm/exynos: fix wrong return check for platform_device_register_simple drm/exynos: add device tree support for fimc ipp driver drm/exynos: rework fimc clocks handling drm/exynos: remove redundant devm_kfree() drm/exynos: enable FIMD clocks Revert "drm/exynos: prepare FIMD clocks"
This commit is contained in:
Коммит
8b1f3dc8bb
|
@ -25,8 +25,8 @@ config DRM_EXYNOS_DMABUF
|
||||||
config DRM_EXYNOS_FIMD
|
config DRM_EXYNOS_FIMD
|
||||||
bool "Exynos DRM FIMD"
|
bool "Exynos DRM FIMD"
|
||||||
depends on OF && DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM
|
depends on OF && DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM
|
||||||
select OF_VIDEOMODE
|
|
||||||
select FB_MODE_HELPERS
|
select FB_MODE_HELPERS
|
||||||
|
select VIDEOMODE_HELPERS
|
||||||
help
|
help
|
||||||
Choose this option if you want to use Exynos FIMD for DRM.
|
Choose this option if you want to use Exynos FIMD for DRM.
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ config DRM_EXYNOS_IPP
|
||||||
|
|
||||||
config DRM_EXYNOS_FIMC
|
config DRM_EXYNOS_FIMC
|
||||||
bool "Exynos DRM FIMC"
|
bool "Exynos DRM FIMC"
|
||||||
depends on DRM_EXYNOS_IPP
|
depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF
|
||||||
help
|
help
|
||||||
Choose this option if you want to use Exynos FIMC for DRM.
|
Choose this option if you want to use Exynos FIMC for DRM.
|
||||||
|
|
||||||
|
|
|
@ -380,6 +380,10 @@ static int __init exynos_drm_init(void)
|
||||||
ret = platform_driver_register(&ipp_driver);
|
ret = platform_driver_register(&ipp_driver);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_ipp;
|
goto out_ipp;
|
||||||
|
|
||||||
|
ret = exynos_platform_device_ipp_register();
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_ipp_dev;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = platform_driver_register(&exynos_drm_platform_driver);
|
ret = platform_driver_register(&exynos_drm_platform_driver);
|
||||||
|
@ -388,7 +392,7 @@ static int __init exynos_drm_init(void)
|
||||||
|
|
||||||
exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
|
exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (IS_ERR_OR_NULL(exynos_drm_pdev)) {
|
if (IS_ERR(exynos_drm_pdev)) {
|
||||||
ret = PTR_ERR(exynos_drm_pdev);
|
ret = PTR_ERR(exynos_drm_pdev);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -400,6 +404,8 @@ out:
|
||||||
|
|
||||||
out_drm:
|
out_drm:
|
||||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||||
|
exynos_platform_device_ipp_unregister();
|
||||||
|
out_ipp_dev:
|
||||||
platform_driver_unregister(&ipp_driver);
|
platform_driver_unregister(&ipp_driver);
|
||||||
out_ipp:
|
out_ipp:
|
||||||
#endif
|
#endif
|
||||||
|
@ -456,6 +462,7 @@ static void __exit exynos_drm_exit(void)
|
||||||
platform_driver_unregister(&exynos_drm_platform_driver);
|
platform_driver_unregister(&exynos_drm_platform_driver);
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||||
|
exynos_platform_device_ipp_unregister();
|
||||||
platform_driver_unregister(&ipp_driver);
|
platform_driver_unregister(&ipp_driver);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -322,13 +322,23 @@ 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
|
* this function registers exynos drm hdmi platform device. It ensures only one
|
||||||
* instance of the device is created.
|
* instance of the device is created.
|
||||||
*/
|
*/
|
||||||
extern int exynos_platform_device_hdmi_register(void);
|
int exynos_platform_device_hdmi_register(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this function unregisters exynos drm hdmi platform device if it exists.
|
* this function unregisters exynos drm hdmi platform device if it exists.
|
||||||
*/
|
*/
|
||||||
void exynos_platform_device_hdmi_unregister(void);
|
void exynos_platform_device_hdmi_unregister(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this function registers exynos drm ipp platform device.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
extern struct platform_driver fimd_driver;
|
extern struct platform_driver fimd_driver;
|
||||||
extern struct platform_driver hdmi_driver;
|
extern struct platform_driver hdmi_driver;
|
||||||
extern struct platform_driver mixer_driver;
|
extern struct platform_driver mixer_driver;
|
||||||
|
|
|
@ -12,11 +12,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <plat/map-base.h>
|
|
||||||
|
|
||||||
#include <drm/drmP.h>
|
#include <drm/drmP.h>
|
||||||
#include <drm/exynos_drm.h>
|
#include <drm/exynos_drm.h>
|
||||||
|
@ -76,6 +77,27 @@ enum fimc_wb {
|
||||||
FIMC_WB_B,
|
FIMC_WB_B,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FIMC_CLK_LCLK,
|
||||||
|
FIMC_CLK_GATE,
|
||||||
|
FIMC_CLK_WB_A,
|
||||||
|
FIMC_CLK_WB_B,
|
||||||
|
FIMC_CLK_MUX,
|
||||||
|
FIMC_CLK_PARENT,
|
||||||
|
FIMC_CLKS_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const fimc_clock_names[] = {
|
||||||
|
[FIMC_CLK_LCLK] = "sclk_fimc",
|
||||||
|
[FIMC_CLK_GATE] = "fimc",
|
||||||
|
[FIMC_CLK_WB_A] = "pxl_async0",
|
||||||
|
[FIMC_CLK_WB_B] = "pxl_async1",
|
||||||
|
[FIMC_CLK_MUX] = "mux",
|
||||||
|
[FIMC_CLK_PARENT] = "parent",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A structure of scaler.
|
* A structure of scaler.
|
||||||
*
|
*
|
||||||
|
@ -118,15 +140,6 @@ struct fimc_capability {
|
||||||
u32 rl_h_rot;
|
u32 rl_h_rot;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* A structure of fimc driver data.
|
|
||||||
*
|
|
||||||
* @parent_clk: name of parent clock.
|
|
||||||
*/
|
|
||||||
struct fimc_driverdata {
|
|
||||||
char *parent_clk;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A structure of fimc context.
|
* A structure of fimc context.
|
||||||
*
|
*
|
||||||
|
@ -134,13 +147,10 @@ struct fimc_driverdata {
|
||||||
* @regs_res: register resources.
|
* @regs_res: register resources.
|
||||||
* @regs: memory mapped io registers.
|
* @regs: memory mapped io registers.
|
||||||
* @lock: locking of operations.
|
* @lock: locking of operations.
|
||||||
* @sclk_fimc_clk: fimc source clock.
|
* @clocks: fimc clocks.
|
||||||
* @fimc_clk: fimc clock.
|
* @clk_frequency: LCLK clock frequency.
|
||||||
* @wb_clk: writeback a clock.
|
* @sysreg: handle to SYSREG block regmap.
|
||||||
* @wb_b_clk: writeback b clock.
|
|
||||||
* @sc: scaler infomations.
|
* @sc: scaler infomations.
|
||||||
* @odr: ordering of YUV.
|
|
||||||
* @ver: fimc version.
|
|
||||||
* @pol: porarity of writeback.
|
* @pol: porarity of writeback.
|
||||||
* @id: fimc id.
|
* @id: fimc id.
|
||||||
* @irq: irq number.
|
* @irq: irq number.
|
||||||
|
@ -151,12 +161,10 @@ struct fimc_context {
|
||||||
struct resource *regs_res;
|
struct resource *regs_res;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct clk *sclk_fimc_clk;
|
struct clk *clocks[FIMC_CLKS_MAX];
|
||||||
struct clk *fimc_clk;
|
u32 clk_frequency;
|
||||||
struct clk *wb_clk;
|
struct regmap *sysreg;
|
||||||
struct clk *wb_b_clk;
|
|
||||||
struct fimc_scaler sc;
|
struct fimc_scaler sc;
|
||||||
struct fimc_driverdata *ddata;
|
|
||||||
struct exynos_drm_ipp_pol pol;
|
struct exynos_drm_ipp_pol pol;
|
||||||
int id;
|
int id;
|
||||||
int irq;
|
int irq;
|
||||||
|
@ -200,17 +208,13 @@ static void fimc_sw_reset(struct fimc_context *ctx)
|
||||||
fimc_write(0x0, EXYNOS_CIFCNTSEQ);
|
fimc_write(0x0, EXYNOS_CIFCNTSEQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
|
static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
|
||||||
{
|
{
|
||||||
u32 camblk_cfg;
|
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s\n", __func__);
|
DRM_DEBUG_KMS("%s\n", __func__);
|
||||||
|
|
||||||
camblk_cfg = readl(SYSREG_CAMERA_BLK);
|
return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK,
|
||||||
camblk_cfg &= ~(SYSREG_FIMD0WB_DEST_MASK);
|
SYSREG_FIMD0WB_DEST_MASK,
|
||||||
camblk_cfg |= ctx->id << (SYSREG_FIMD0WB_DEST_SHIFT);
|
ctx->id << SYSREG_FIMD0WB_DEST_SHIFT);
|
||||||
|
|
||||||
writel(camblk_cfg, SYSREG_CAMERA_BLK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb)
|
static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb)
|
||||||
|
@ -1301,14 +1305,12 @@ static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable)
|
||||||
DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
|
DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
clk_enable(ctx->sclk_fimc_clk);
|
clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
|
||||||
clk_enable(ctx->fimc_clk);
|
clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]);
|
||||||
clk_enable(ctx->wb_clk);
|
|
||||||
ctx->suspended = false;
|
ctx->suspended = false;
|
||||||
} else {
|
} else {
|
||||||
clk_disable(ctx->sclk_fimc_clk);
|
clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
|
||||||
clk_disable(ctx->fimc_clk);
|
clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]);
|
||||||
clk_disable(ctx->wb_clk);
|
|
||||||
ctx->suspended = true;
|
ctx->suspended = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1613,7 +1615,11 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
|
||||||
fimc_handle_lastend(ctx, true);
|
fimc_handle_lastend(ctx, true);
|
||||||
|
|
||||||
/* setup FIMD */
|
/* setup FIMD */
|
||||||
fimc_set_camblk_fimd0_wb(ctx);
|
ret = fimc_set_camblk_fimd0_wb(ctx);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "camblk setup failed.\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
set_wb.enable = 1;
|
set_wb.enable = 1;
|
||||||
set_wb.refresh = property->refresh_rate;
|
set_wb.refresh = property->refresh_rate;
|
||||||
|
@ -1713,75 +1719,117 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
|
||||||
fimc_write(cfg, EXYNOS_CIGCTRL);
|
fimc_write(cfg, EXYNOS_CIGCTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fimc_put_clocks(struct fimc_context *ctx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < FIMC_CLKS_MAX; i++) {
|
||||||
|
if (IS_ERR(ctx->clocks[i]))
|
||||||
|
continue;
|
||||||
|
clk_put(ctx->clocks[i]);
|
||||||
|
ctx->clocks[i] = ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fimc_setup_clocks(struct fimc_context *ctx)
|
||||||
|
{
|
||||||
|
struct device *fimc_dev = ctx->ippdrv.dev;
|
||||||
|
struct device *dev;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
for (i = 0; i < FIMC_CLKS_MAX; i++)
|
||||||
|
ctx->clocks[i] = ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
for (i = 0; i < FIMC_CLKS_MAX; i++) {
|
||||||
|
if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B)
|
||||||
|
dev = fimc_dev->parent;
|
||||||
|
else
|
||||||
|
dev = fimc_dev;
|
||||||
|
|
||||||
|
ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]);
|
||||||
|
if (IS_ERR(ctx->clocks[i])) {
|
||||||
|
if (i >= FIMC_CLK_MUX)
|
||||||
|
break;
|
||||||
|
ret = PTR_ERR(ctx->clocks[i]);
|
||||||
|
dev_err(fimc_dev, "failed to get clock: %s\n",
|
||||||
|
fimc_clock_names[i]);
|
||||||
|
goto e_clk_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional FIMC LCLK parent clock setting */
|
||||||
|
if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) {
|
||||||
|
ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX],
|
||||||
|
ctx->clocks[FIMC_CLK_PARENT]);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(fimc_dev, "failed to set parent.\n");
|
||||||
|
goto e_clk_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency);
|
||||||
|
if (ret < 0)
|
||||||
|
goto e_clk_free;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]);
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
e_clk_free:
|
||||||
|
fimc_put_clocks(ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fimc_parse_dt(struct fimc_context *ctx)
|
||||||
|
{
|
||||||
|
struct device_node *node = ctx->ippdrv.dev->of_node;
|
||||||
|
|
||||||
|
/* Handle only devices that support the LCD Writeback data path */
|
||||||
|
if (!of_property_read_bool(node, "samsung,lcd-wb"))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (of_property_read_u32(node, "clock-frequency",
|
||||||
|
&ctx->clk_frequency))
|
||||||
|
ctx->clk_frequency = FIMC_DEFAULT_LCLK_FREQUENCY;
|
||||||
|
|
||||||
|
ctx->id = of_alias_get_id(node, "fimc");
|
||||||
|
|
||||||
|
if (ctx->id < 0) {
|
||||||
|
dev_err(ctx->ippdrv.dev, "failed to get node alias id.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int fimc_probe(struct platform_device *pdev)
|
static int fimc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct fimc_context *ctx;
|
struct fimc_context *ctx;
|
||||||
struct clk *parent_clk;
|
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct exynos_drm_ippdrv *ippdrv;
|
struct exynos_drm_ippdrv *ippdrv;
|
||||||
struct exynos_drm_fimc_pdata *pdata;
|
|
||||||
struct fimc_driverdata *ddata;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pdata = pdev->dev.platform_data;
|
if (!dev->of_node) {
|
||||||
if (!pdata) {
|
dev_err(dev, "device tree node not found.\n");
|
||||||
dev_err(dev, "no platform data specified.\n");
|
return -ENODEV;
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ddata = (struct fimc_driverdata *)
|
ctx->ippdrv.dev = dev;
|
||||||
platform_get_device_id(pdev)->driver_data;
|
|
||||||
|
|
||||||
/* clock control */
|
ret = fimc_parse_dt(ctx);
|
||||||
ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc");
|
if (ret < 0)
|
||||||
if (IS_ERR(ctx->sclk_fimc_clk)) {
|
return ret;
|
||||||
dev_err(dev, "failed to get src fimc clock.\n");
|
|
||||||
return PTR_ERR(ctx->sclk_fimc_clk);
|
ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||||
|
"samsung,sysreg");
|
||||||
|
if (IS_ERR(ctx->sysreg)) {
|
||||||
|
dev_err(dev, "syscon regmap lookup failed.\n");
|
||||||
|
return PTR_ERR(ctx->sysreg);
|
||||||
}
|
}
|
||||||
clk_enable(ctx->sclk_fimc_clk);
|
|
||||||
|
|
||||||
ctx->fimc_clk = devm_clk_get(dev, "fimc");
|
|
||||||
if (IS_ERR(ctx->fimc_clk)) {
|
|
||||||
dev_err(dev, "failed to get fimc clock.\n");
|
|
||||||
clk_disable(ctx->sclk_fimc_clk);
|
|
||||||
return PTR_ERR(ctx->fimc_clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->wb_clk = devm_clk_get(dev, "pxl_async0");
|
|
||||||
if (IS_ERR(ctx->wb_clk)) {
|
|
||||||
dev_err(dev, "failed to get writeback a clock.\n");
|
|
||||||
clk_disable(ctx->sclk_fimc_clk);
|
|
||||||
return PTR_ERR(ctx->wb_clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1");
|
|
||||||
if (IS_ERR(ctx->wb_b_clk)) {
|
|
||||||
dev_err(dev, "failed to get writeback b clock.\n");
|
|
||||||
clk_disable(ctx->sclk_fimc_clk);
|
|
||||||
return PTR_ERR(ctx->wb_b_clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
parent_clk = devm_clk_get(dev, ddata->parent_clk);
|
|
||||||
|
|
||||||
if (IS_ERR(parent_clk)) {
|
|
||||||
dev_err(dev, "failed to get parent clock.\n");
|
|
||||||
clk_disable(ctx->sclk_fimc_clk);
|
|
||||||
return PTR_ERR(parent_clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) {
|
|
||||||
dev_err(dev, "failed to set parent.\n");
|
|
||||||
clk_disable(ctx->sclk_fimc_clk);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
devm_clk_put(dev, parent_clk);
|
|
||||||
clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate);
|
|
||||||
|
|
||||||
/* resource memory */
|
/* resource memory */
|
||||||
ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
@ -1804,13 +1852,11 @@ static int fimc_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* context initailization */
|
ret = fimc_setup_clocks(ctx);
|
||||||
ctx->id = pdev->id;
|
if (ret < 0)
|
||||||
ctx->pol = pdata->pol;
|
goto err_free_irq;
|
||||||
ctx->ddata = ddata;
|
|
||||||
|
|
||||||
ippdrv = &ctx->ippdrv;
|
ippdrv = &ctx->ippdrv;
|
||||||
ippdrv->dev = dev;
|
|
||||||
ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
|
ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
|
||||||
ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops;
|
ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops;
|
||||||
ippdrv->check_property = fimc_ippdrv_check_property;
|
ippdrv->check_property = fimc_ippdrv_check_property;
|
||||||
|
@ -1820,7 +1866,7 @@ static int fimc_probe(struct platform_device *pdev)
|
||||||
ret = fimc_init_prop_list(ippdrv);
|
ret = fimc_init_prop_list(ippdrv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to init property list.\n");
|
dev_err(dev, "failed to init property list.\n");
|
||||||
goto err_get_irq;
|
goto err_put_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
|
DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
|
||||||
|
@ -1835,17 +1881,18 @@ static int fimc_probe(struct platform_device *pdev)
|
||||||
ret = exynos_drm_ippdrv_register(ippdrv);
|
ret = exynos_drm_ippdrv_register(ippdrv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to register drm fimc device.\n");
|
dev_err(dev, "failed to register drm fimc device.\n");
|
||||||
goto err_ippdrv_register;
|
goto err_pm_dis;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&pdev->dev, "drm fimc registered successfully.\n");
|
dev_info(&pdev->dev, "drm fimc registered successfully.\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_ippdrv_register:
|
err_pm_dis:
|
||||||
devm_kfree(dev, ippdrv->prop_list);
|
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
err_get_irq:
|
err_put_clk:
|
||||||
|
fimc_put_clocks(ctx);
|
||||||
|
err_free_irq:
|
||||||
free_irq(ctx->irq, ctx);
|
free_irq(ctx->irq, ctx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1857,10 +1904,10 @@ static int fimc_remove(struct platform_device *pdev)
|
||||||
struct fimc_context *ctx = get_fimc_context(dev);
|
struct fimc_context *ctx = get_fimc_context(dev);
|
||||||
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
|
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
|
||||||
|
|
||||||
devm_kfree(dev, ippdrv->prop_list);
|
|
||||||
exynos_drm_ippdrv_unregister(ippdrv);
|
exynos_drm_ippdrv_unregister(ippdrv);
|
||||||
mutex_destroy(&ctx->lock);
|
mutex_destroy(&ctx->lock);
|
||||||
|
|
||||||
|
fimc_put_clocks(ctx);
|
||||||
pm_runtime_set_suspended(dev);
|
pm_runtime_set_suspended(dev);
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
@ -1915,36 +1962,22 @@ static int fimc_runtime_resume(struct device *dev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct fimc_driverdata exynos4210_fimc_data = {
|
|
||||||
.parent_clk = "mout_mpll",
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct fimc_driverdata exynos4410_fimc_data = {
|
|
||||||
.parent_clk = "mout_mpll_user",
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct platform_device_id fimc_driver_ids[] = {
|
|
||||||
{
|
|
||||||
.name = "exynos4210-fimc",
|
|
||||||
.driver_data = (unsigned long)&exynos4210_fimc_data,
|
|
||||||
}, {
|
|
||||||
.name = "exynos4412-fimc",
|
|
||||||
.driver_data = (unsigned long)&exynos4410_fimc_data,
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
|
|
||||||
|
|
||||||
static const struct dev_pm_ops fimc_pm_ops = {
|
static const struct dev_pm_ops fimc_pm_ops = {
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
|
SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
|
||||||
SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
|
SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id fimc_of_match[] = {
|
||||||
|
{ .compatible = "samsung,exynos4210-fimc" },
|
||||||
|
{ .compatible = "samsung,exynos4212-fimc" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
struct platform_driver fimc_driver = {
|
struct platform_driver fimc_driver = {
|
||||||
.probe = fimc_probe,
|
.probe = fimc_probe,
|
||||||
.remove = fimc_remove,
|
.remove = fimc_remove,
|
||||||
.id_table = fimc_driver_ids,
|
|
||||||
.driver = {
|
.driver = {
|
||||||
|
.of_match_table = fimc_of_match,
|
||||||
.name = "exynos-drm-fimc",
|
.name = "exynos-drm-fimc",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pm = &fimc_pm_ops,
|
.pm = &fimc_pm_ops,
|
||||||
|
|
|
@ -801,18 +801,18 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
|
||||||
if (enable) {
|
if (enable) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_enable(ctx->bus_clk);
|
ret = clk_prepare_enable(ctx->bus_clk);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = clk_enable(ctx->lcd_clk);
|
ret = clk_prepare_enable(ctx->lcd_clk);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
clk_disable(ctx->bus_clk);
|
clk_disable_unprepare(ctx->bus_clk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clk_disable(ctx->lcd_clk);
|
clk_disable_unprepare(ctx->lcd_clk);
|
||||||
clk_disable(ctx->bus_clk);
|
clk_disable_unprepare(ctx->bus_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -949,16 +949,6 @@ static int fimd_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare(ctx->bus_clk);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = clk_prepare(ctx->lcd_clk);
|
|
||||||
if (ret < 0) {
|
|
||||||
clk_unprepare(ctx->bus_clk);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->vidcon0 = pdata->vidcon0;
|
ctx->vidcon0 = pdata->vidcon0;
|
||||||
ctx->vidcon1 = pdata->vidcon1;
|
ctx->vidcon1 = pdata->vidcon1;
|
||||||
ctx->default_win = pdata->default_win;
|
ctx->default_win = pdata->default_win;
|
||||||
|
@ -1006,9 +996,6 @@ static int fimd_remove(struct platform_device *pdev)
|
||||||
if (ctx->suspended)
|
if (ctx->suspended)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
clk_unprepare(ctx->lcd_clk);
|
|
||||||
clk_unprepare(ctx->bus_clk);
|
|
||||||
|
|
||||||
pm_runtime_set_suspended(dev);
|
pm_runtime_set_suspended(dev);
|
||||||
pm_runtime_put_sync(dev);
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
|
|
|
@ -682,7 +682,8 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
|
||||||
args->pitch = args->width * ((args->bpp + 7) / 8);
|
args->pitch = args->width * ((args->bpp + 7) / 8);
|
||||||
args->size = args->pitch * args->height;
|
args->size = args->pitch * args->height;
|
||||||
|
|
||||||
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
|
exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG |
|
||||||
|
EXYNOS_BO_WC, args->size);
|
||||||
if (IS_ERR(exynos_gem_obj))
|
if (IS_ERR(exynos_gem_obj))
|
||||||
return PTR_ERR(exynos_gem_obj);
|
return PTR_ERR(exynos_gem_obj);
|
||||||
|
|
||||||
|
|
|
@ -51,21 +51,27 @@ struct drm_hdmi_context {
|
||||||
|
|
||||||
int exynos_platform_device_hdmi_register(void)
|
int exynos_platform_device_hdmi_register(void)
|
||||||
{
|
{
|
||||||
|
struct platform_device *pdev;
|
||||||
|
|
||||||
if (exynos_drm_hdmi_pdev)
|
if (exynos_drm_hdmi_pdev)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
|
|
||||||
exynos_drm_hdmi_pdev = platform_device_register_simple(
|
pdev = platform_device_register_simple(
|
||||||
"exynos-drm-hdmi", -1, NULL, 0);
|
"exynos-drm-hdmi", -1, NULL, 0);
|
||||||
if (IS_ERR_OR_NULL(exynos_drm_hdmi_pdev))
|
if (IS_ERR(pdev))
|
||||||
return PTR_ERR(exynos_drm_hdmi_pdev);
|
return PTR_ERR(pdev);
|
||||||
|
|
||||||
|
exynos_drm_hdmi_pdev = pdev;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_platform_device_hdmi_unregister(void)
|
void exynos_platform_device_hdmi_unregister(void)
|
||||||
{
|
{
|
||||||
if (exynos_drm_hdmi_pdev)
|
if (exynos_drm_hdmi_pdev) {
|
||||||
platform_device_unregister(exynos_drm_hdmi_pdev);
|
platform_device_unregister(exynos_drm_hdmi_pdev);
|
||||||
|
exynos_drm_hdmi_pdev = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
|
void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev))
|
#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev))
|
||||||
#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M)
|
#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M)
|
||||||
|
|
||||||
|
/* platform device pointer for ipp device. */
|
||||||
|
static struct platform_device *exynos_drm_ipp_pdev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A structure of event.
|
* A structure of event.
|
||||||
*
|
*
|
||||||
|
@ -102,6 +105,30 @@ static LIST_HEAD(exynos_drm_ippdrv_list);
|
||||||
static DEFINE_MUTEX(exynos_drm_ippdrv_lock);
|
static DEFINE_MUTEX(exynos_drm_ippdrv_lock);
|
||||||
static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list);
|
static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list);
|
||||||
|
|
||||||
|
int exynos_platform_device_ipp_register(void)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev;
|
||||||
|
|
||||||
|
if (exynos_drm_ipp_pdev)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
pdev = platform_device_register_simple("exynos-drm-ipp", -1, NULL, 0);
|
||||||
|
if (IS_ERR(pdev))
|
||||||
|
return PTR_ERR(pdev);
|
||||||
|
|
||||||
|
exynos_drm_ipp_pdev = pdev;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_platform_device_ipp_unregister(void)
|
||||||
|
{
|
||||||
|
if (exynos_drm_ipp_pdev) {
|
||||||
|
platform_device_unregister(exynos_drm_ipp_pdev);
|
||||||
|
exynos_drm_ipp_pdev = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
|
int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
|
||||||
{
|
{
|
||||||
DRM_DEBUG_KMS("%s\n", __func__);
|
DRM_DEBUG_KMS("%s\n", __func__);
|
||||||
|
|
|
@ -1373,11 +1373,10 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdata->type == HDMI_TYPE13) {
|
if (hdata->type == HDMI_TYPE13)
|
||||||
hdmiphy_data = hdmiphy_v13_configs[i].conf;
|
hdmiphy_data = hdmiphy_v13_configs[i].conf;
|
||||||
} else {
|
else
|
||||||
hdmiphy_data = hdmiphy_v14_configs[i].conf;
|
hdmiphy_data = hdmiphy_v14_configs[i].conf;
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer, hdmiphy_data, 32);
|
memcpy(buffer, hdmiphy_data, 32);
|
||||||
ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
|
ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
|
||||||
|
@ -1653,11 +1652,10 @@ static void hdmi_mode_set(void *ctx, void *mode)
|
||||||
m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
|
m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
|
||||||
"INTERLACED" : "PROGERESSIVE");
|
"INTERLACED" : "PROGERESSIVE");
|
||||||
|
|
||||||
if (hdata->type == HDMI_TYPE13) {
|
if (hdata->type == HDMI_TYPE13)
|
||||||
hdmi_v13_mode_set(hdata, mode);
|
hdmi_v13_mode_set(hdata, mode);
|
||||||
} else {
|
else
|
||||||
hdmi_v14_mode_set(hdata, mode);
|
hdmi_v14_mode_set(hdata, mode);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_get_max_resol(void *ctx, unsigned int *width,
|
static void hdmi_get_max_resol(void *ctx, unsigned int *width,
|
||||||
|
|
|
@ -643,12 +643,14 @@ static void mixer_win_reset(struct mixer_context *ctx)
|
||||||
/* setting graphical layers */
|
/* setting graphical layers */
|
||||||
val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
|
val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
|
||||||
val |= MXR_GRP_CFG_WIN_BLEND_EN;
|
val |= MXR_GRP_CFG_WIN_BLEND_EN;
|
||||||
val |= MXR_GRP_CFG_BLEND_PRE_MUL;
|
|
||||||
val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
|
|
||||||
val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
|
val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
|
||||||
|
|
||||||
/* the same configuration for both layers */
|
/* Don't blend layer 0 onto the mixer background */
|
||||||
mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
|
mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
|
||||||
|
|
||||||
|
/* Blend layer 1 into layer 0 */
|
||||||
|
val |= MXR_GRP_CFG_BLEND_PRE_MUL;
|
||||||
|
val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
|
||||||
mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
|
mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
|
||||||
|
|
||||||
/* setting video layers */
|
/* setting video layers */
|
||||||
|
|
|
@ -661,8 +661,7 @@
|
||||||
#define EXYNOS_CLKSRC_SCLK (1 << 1)
|
#define EXYNOS_CLKSRC_SCLK (1 << 1)
|
||||||
|
|
||||||
/* SYSREG for FIMC writeback */
|
/* SYSREG for FIMC writeback */
|
||||||
#define SYSREG_CAMERA_BLK (S3C_VA_SYS + 0x0218)
|
#define SYSREG_CAMERA_BLK (0x0218)
|
||||||
#define SYSREG_ISP_BLK (S3C_VA_SYS + 0x020c)
|
|
||||||
#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
|
#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
|
||||||
#define SYSREG_FIMD0WB_DEST_SHIFT 23
|
#define SYSREG_FIMD0WB_DEST_SHIFT 23
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче