Merge branch 'odroidxu4-4.9.y' of github.com:hardkernel/linux into odroidxu4-4.9.y

This commit is contained in:
Mauro (mdrjr) Ribeiro
2017-03-06 18:38:29 +09:00
8 changed files with 340 additions and 300 deletions

View File

@@ -3,7 +3,8 @@
G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs.
Required properties:
- compatible: should be "samsung,exynos5-gsc"
- compatible: should be "samsung,exynos5-gsc" (for Exynos 5250, 5420 and
5422 SoCs) or "samsung,exynos5433-gsc" (Exynos 5433)
- reg: should contain G-Scaler physical address location and length.
- interrupts: should contain G-Scaler interrupt number

View File

@@ -191,6 +191,15 @@
clock-names = "fout_epll", "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in";
};
g2d@10850000 {
compatible = "samsung,exynos5250-g2d";
reg = <0x10850000 0x1000>;
interrupts = <0 91 0>;
clocks = <&clock CLK_G2D>;
clock-names = "fimg2d";
iommus = <&sysmmu_g2dr>, <&sysmmu_g2dw>;
};
mfc: codec@11000000 {
compatible = "samsung,mfc-v7";
reg = <0x11000000 0x10000>;

View File

@@ -81,7 +81,7 @@
cooling-min-state = <0>;
cooling-max-state = <3>;
#cooling-cells = <2>;
cooling-levels = <0 150 190 252>;
cooling-levels = <0 110 170 230>;
};
mali: mali@0x11800000 {
@@ -124,90 +124,28 @@
thermal-zones {
cpu0_thermal: cpu0-thermal {
thermal-sensors = <&tmu_cpu0 0 &tmu_cpu1 0 &tmu_cpu2 0 &tmu_cpu3 0>;
polling-delay-passive = <250>;
polling-delay = <1000>;
trips {
cpu_alert0: cpu-alert-0 {
temperature = <70000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_alert1: cpu-alert-1 {
temperature = <75000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_alert2: cpu-alert-2 {
temperature = <80000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_alert3: cpu-alert-3 {
temperature = <90000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_alert4: cpu-alert-4 {
temperature = <95000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_alert5: cpu-alert-5 {
temperature = <103000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_alert6: cpu-alert-6 {
temperature = <110000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "passive";
};
cpu_criti0: cpu-crit-0 {
temperature = <115000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "critical";
};
};
cooling-maps {
map0 {
trip = <&cpu_alert0>;
cooling-device = <&fan0 0 1>;
};
map1 {
trip = <&cpu_alert1>;
cooling-device = <&fan0 1 2>;
};
map2 {
trip = <&cpu_alert2>;
cooling-device = <&fan0 2 3>;
};
/*
* First trip for A7: 1000Mhz
* First trip for A15: 1400Mhz
*/
map3 {
trip = <&cpu_alert3>;
cooling-device = <&cpu0 0 6>;
};
map4 {
trip = <&cpu_alert3>;
cooling-device = <&cpu4 0 3>;
};
/*
* Second trip for A15: 600Mhz
* Second trip for A7: 600Mhz
*/
map5 {
trip = <&cpu_alert4>;
cooling-device = <&cpu0 3 7>;
};
map6 {
trip = <&cpu_alert4>;
cooling-device = <&cpu4 3 14>;
};
};
thermal-sensors = <&tmu_cpu0 0>;
#define CPU_THERMAL_ZONE_NUM 0
#include "exynos5422-odroidxu3-trip-points.dtsi"
#undef CPU_THERMAL_ZONE_NUM
};
cpu1_thermal: cpu1-thermal {
thermal-sensors = <&tmu_cpu1 0>;
#define CPU_THERMAL_ZONE_NUM 1
#include "exynos5422-odroidxu3-trip-points.dtsi"
#undef CPU_THERMAL_ZONE_NUM
};
cpu2_thermal: cpu2-thermal {
thermal-sensors = <&tmu_cpu2 0>;
#define CPU_THERMAL_ZONE_NUM 2
#include "exynos5422-odroidxu3-trip-points.dtsi"
#undef CPU_THERMAL_ZONE_NUM
};
cpu3_thermal: cpu3-thermal {
thermal-sensors = <&tmu_cpu3 0>;
#define CPU_THERMAL_ZONE_NUM 3
#include "exynos5422-odroidxu3-trip-points.dtsi"
#undef CPU_THERMAL_ZONE_NUM
};
};
};

View File

@@ -0,0 +1,100 @@
/*
* Device tree sources for default OdroidXU3/Exynos5422 thermal zone definition
*
* Copyright (c) 2015 Lukasz Majewski <l.majewski@samsung.com>
* Anand Moon <linux.amoon@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#define _TOKENPASTE(x, y) x ## y
#define TOKENPASTE(x, y) _TOKENPASTE(x, y)
#define UNIQIFY(label) TOKENPASTE(label, CPU_THERMAL_ZONE_NUM)
polling-delay-passive = <250>;
polling-delay = <1000>;
trips {
UNIQIFY(cpu_alert0): cpu-alert-0 {
temperature = <70000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "active";
};
UNIQIFY(cpu_alert1): cpu-alert-1 {
temperature = <75000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "active";
};
UNIQIFY(cpu_alert2): cpu-alert-2 {
temperature = <80000>; /* millicelsius */
hysteresis = <10000>; /* millicelsius */
type = "active";
};
UNIQIFY(cpu_alert3): cpu-alert-3 {
temperature = <85000>; /* millicelsius */
hysteresis = <3000>; /* millicelsius */
type = "passive";
};
UNIQIFY(cpu_alert4): cpu-alert-4 {
temperature = <90000>; /* millicelsius */
hysteresis = <3000>; /* millicelsius */
type = "passive";
};
UNIQIFY(cpu_alert5): cpu-alert-5 {
temperature = <95000>; /* millicelsius */
hysteresis = <3000>; /* millicelsius */
type = "passive";
};
UNIQIFY(cpu_criti0): cpu-crit-0 {
temperature = <115000>; /* millicelsius */
hysteresis = <3000>; /* millicelsius */
type = "critical";
};
};
cooling-maps {
map0 {
trip = <&UNIQIFY(cpu_alert0)>;
cooling-device = <&fan0 0 1>;
};
map1 {
trip = <&UNIQIFY(cpu_alert1)>;
cooling-device = <&fan0 1 2>;
};
map2 {
trip = <&UNIQIFY(cpu_alert2)>;
cooling-device = <&fan0 2 3>;
};
/*
* When reaching cpu_alert3, reduce A15 cores by 1 step.
* The 2GHz step causes high thermals on multithreaded workloads
* so better performance is gained by managing it out early.
*/
map3 {
trip = <&UNIQIFY(cpu_alert3)>;
cooling-device = <&cpu4 0 1>;
};
/*
* When reaching cpu_alert4, reduce A15 cores by 3 steps
* to further manage the performance level while keeping
* thermals under control.
*/
map4 {
trip = <&UNIQIFY(cpu_alert4)>;
cooling-device = <&cpu4 2 4>;
};
/*
* When reaching cpu_alert5, reduce all CPUs to ensure thermal
* safety. A7 cores don't produce much thermal load so they are
* reduced less to optimise performance.
*/
map5 {
trip = <&UNIQIFY(cpu_alert5)>;
cooling-device = <&cpu0 0 2>;
};
map6 {
trip = <&UNIQIFY(cpu_alert5)>;
cooling-device = <&cpu4 5 14>;
};
};

View File

@@ -3229,7 +3229,7 @@ CONFIG_VIDEO_EXYNOS4_ISP_DMA_CAPTURE=y
# CONFIG_VIDEO_XILINX is not set
CONFIG_V4L_MEM2MEM_DRIVERS=y
# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set
CONFIG_VIDEO_SAMSUNG_S5P_G2D=y
# CONFIG_VIDEO_SAMSUNG_S5P_G2D is not set
CONFIG_VIDEO_SAMSUNG_S5P_JPEG=y
CONFIG_VIDEO_SAMSUNG_S5P_MFC=y
CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=y
@@ -3545,6 +3545,7 @@ CONFIG_DRM_EXYNOS_HDMI=y
#
# Sub-drivers
#
CONFIG_DRM_EXYNOS_G2D=y
CONFIG_DRM_EXYNOS_IPP=y
CONFIG_DRM_EXYNOS_FIMC=y
CONFIG_DRM_EXYNOS_ROTATOR=y

View File

@@ -24,12 +24,11 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <media/v4l2-ioctl.h>
#include "gsc-core.h"
#define GSC_CLOCK_GATE_NAME "gscl"
static const struct gsc_fmt gsc_formats[] = {
{
.name = "RGB565",
@@ -39,8 +38,8 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 1,
}, {
.name = "XRGB-8-8-8-8, 32 bpp",
.pixelformat = V4L2_PIX_FMT_RGB32,
.name = "BGRX-8-8-8-8, 32 bpp",
.pixelformat = V4L2_PIX_FMT_BGR32,
.depth = { 32 },
.color = GSC_RGB,
.num_planes = 1,
@@ -409,7 +408,7 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
if (pix_mp->field == V4L2_FIELD_ANY)
pix_mp->field = V4L2_FIELD_NONE;
else if (pix_mp->field != V4L2_FIELD_NONE) {
pr_err("Not supported field order(%d)\n", pix_mp->field);
pr_debug("Not supported field order(%d)\n", pix_mp->field);
return -EINVAL;
}
@@ -441,7 +440,7 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x,
&pix_mp->height, min_h, max_h, mod_y, 0);
if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
pr_info("Image size has been modified from %dx%d to %dx%d",
pr_debug("Image size has been modified from %dx%d to %dx%d\n",
tmp_w, tmp_h, pix_mp->width, pix_mp->height);
pix_mp->num_planes = fmt->num_planes;
@@ -451,12 +450,25 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
else /* SD */
pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
for (i = 0; i < pix_mp->num_planes; ++i) {
int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
pix_mp->plane_fmt[i].bytesperline = bpl;
pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i];
u32 bpl = plane_fmt->bytesperline;
if (fmt->num_comp == 1 && /* Packed */
(bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width))
bpl = pix_mp->width * fmt->depth[i] / 8;
if (fmt->num_comp > 1 && /* Planar */
(bpl == 0 || bpl < pix_mp->width))
bpl = pix_mp->width;
if (i != 0 && fmt->num_comp == 3)
bpl /= 2;
plane_fmt->bytesperline = bpl;
plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height *
fmt->depth[i] / 8,
plane_fmt->sizeimage);
pr_debug("[%d]: bpl: %d, sizeimage: %d",
i, bpl, pix_mp->plane_fmt[i].sizeimage);
}
@@ -964,7 +976,19 @@ static struct gsc_driverdata gsc_v_100_drvdata = {
[3] = &gsc_v_100_variant,
},
.num_entities = 4,
.lclk_frequency = 266000000UL,
.clk_names = { "gscl" },
.num_clocks = 1,
};
static struct gsc_driverdata gsc_5433_drvdata = {
.variant = {
[0] = &gsc_v_100_variant,
[1] = &gsc_v_100_variant,
[2] = &gsc_v_100_variant,
},
.num_entities = 3,
.clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" },
.num_clocks = 4,
};
static const struct of_device_id exynos_gsc_match[] = {
@@ -972,52 +996,135 @@ static const struct of_device_id exynos_gsc_match[] = {
.compatible = "samsung,exynos5-gsc",
.data = &gsc_v_100_drvdata,
},
{
.compatible = "samsung,exynos5433-gsc",
.data = &gsc_5433_drvdata,
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_gsc_match);
static void *gsc_get_drv_data(struct platform_device *pdev)
{
struct gsc_driverdata *driver_data = NULL;
const struct of_device_id *match;
match = of_match_node(exynos_gsc_match, pdev->dev.of_node);
if (match)
driver_data = (struct gsc_driverdata *)match->data;
return driver_data;
}
static void gsc_clk_put(struct gsc_dev *gsc)
{
if (!IS_ERR(gsc->clock))
clk_unprepare(gsc->clock);
}
static int gsc_clk_get(struct gsc_dev *gsc)
static int gsc_probe(struct platform_device *pdev)
{
struct gsc_dev *gsc;
struct resource *res;
struct device *dev = &pdev->dev;
const struct gsc_driverdata *drv_data = of_device_get_match_data(dev);
int ret;
int i;
dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n");
gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
if (!gsc)
return -ENOMEM;
gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
if (IS_ERR(gsc->clock)) {
dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n",
GSC_CLOCK_GATE_NAME);
return PTR_ERR(gsc->clock);
}
ret = clk_prepare(gsc->clock);
if (ret < 0) {
dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n",
GSC_CLOCK_GATE_NAME);
gsc->clock = ERR_PTR(-EINVAL);
ret = of_alias_get_id(pdev->dev.of_node, "gsc");
if (ret < 0)
return ret;
gsc->id = ret;
if (gsc->id >= drv_data->num_entities) {
dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
return -EINVAL;
}
gsc->num_clocks = drv_data->num_clocks;
gsc->variant = drv_data->variant[gsc->id];
gsc->pdev = pdev;
init_waitqueue_head(&gsc->irq_queue);
spin_lock_init(&gsc->slock);
mutex_init(&gsc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gsc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(gsc->regs))
return PTR_ERR(gsc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "failed to get IRQ resource\n");
return -ENXIO;
}
for (i = 0; i < gsc->num_clocks; i++) {
gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]);
if (IS_ERR(gsc->clock[i])) {
dev_err(dev, "failed to get clock: %s\n",
drv_data->clk_names[i]);
return PTR_ERR(gsc->clock[i]);
}
}
for (i = 0; i < gsc->num_clocks; i++) {
ret = clk_prepare_enable(gsc->clock[i]);
if (ret) {
dev_err(dev, "clock prepare failed for clock: %s\n",
drv_data->clk_names[i]);
while (--i >= 0)
clk_disable_unprepare(gsc->clock[i]);
return ret;
}
}
ret = devm_request_irq(dev, res->start, gsc_irq_handler,
0, pdev->name, gsc);
if (ret) {
dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_clk;
}
ret = v4l2_device_register(dev, &gsc->v4l2_dev);
if (ret)
goto err_clk;
ret = gsc_register_m2m_device(gsc);
if (ret)
goto err_v4l2;
platform_set_drvdata(pdev, gsc);
gsc_hw_set_sw_reset(gsc);
gsc_wait_reset(gsc);
vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
err_v4l2:
v4l2_device_unregister(&gsc->v4l2_dev);
err_clk:
for (i = gsc->num_clocks - 1; i >= 0; i--)
clk_disable_unprepare(gsc->clock[i]);
return ret;
}
static int gsc_remove(struct platform_device *pdev)
{
struct gsc_dev *gsc = platform_get_drvdata(pdev);
int i;
pm_runtime_get_sync(&pdev->dev);
gsc_unregister_m2m_device(gsc);
v4l2_device_unregister(&gsc->v4l2_dev);
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
for (i = 0; i < gsc->num_clocks; i++)
clk_disable_unprepare(gsc->clock[i]);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
}
#ifdef CONFIG_PM
static int gsc_m2m_suspend(struct gsc_dev *gsc)
{
unsigned long flags;
@@ -1040,7 +1147,7 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc)
return timeout == 0 ? -EAGAIN : 0;
}
static int gsc_m2m_resume(struct gsc_dev *gsc)
static void gsc_m2m_resume(struct gsc_dev *gsc)
{
struct gsc_ctx *ctx;
unsigned long flags;
@@ -1053,179 +1160,54 @@ static int gsc_m2m_resume(struct gsc_dev *gsc)
if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
return 0;
}
static int gsc_probe(struct platform_device *pdev)
{
struct gsc_dev *gsc;
struct resource *res;
struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev);
struct device *dev = &pdev->dev;
int ret;
gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
if (!gsc)
return -ENOMEM;
ret = of_alias_get_id(pdev->dev.of_node, "gsc");
if (ret < 0)
return ret;
gsc->id = ret;
if (gsc->id >= drv_data->num_entities) {
dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
return -EINVAL;
}
gsc->variant = drv_data->variant[gsc->id];
gsc->pdev = pdev;
init_waitqueue_head(&gsc->irq_queue);
spin_lock_init(&gsc->slock);
mutex_init(&gsc->lock);
gsc->clock = ERR_PTR(-EINVAL);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gsc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(gsc->regs))
return PTR_ERR(gsc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "failed to get IRQ resource\n");
return -ENXIO;
}
ret = gsc_clk_get(gsc);
if (ret)
return ret;
ret = devm_request_irq(dev, res->start, gsc_irq_handler,
0, pdev->name, gsc);
if (ret) {
dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_clk;
}
ret = v4l2_device_register(dev, &gsc->v4l2_dev);
if (ret)
goto err_clk;
ret = gsc_register_m2m_device(gsc);
if (ret)
goto err_v4l2;
platform_set_drvdata(pdev, gsc);
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
goto err_m2m;
vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
pm_runtime_put(dev);
return 0;
err_m2m:
gsc_unregister_m2m_device(gsc);
err_v4l2:
v4l2_device_unregister(&gsc->v4l2_dev);
err_clk:
gsc_clk_put(gsc);
return ret;
}
static int gsc_remove(struct platform_device *pdev)
{
struct gsc_dev *gsc = platform_get_drvdata(pdev);
gsc_unregister_m2m_device(gsc);
v4l2_device_unregister(&gsc->v4l2_dev);
vb2_dma_contig_clear_max_seg_size(&pdev->dev);
pm_runtime_disable(&pdev->dev);
gsc_clk_put(gsc);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
}
static int gsc_runtime_resume(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
int ret = 0;
int i;
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
ret = clk_enable(gsc->clock);
if (ret)
return ret;
for (i = 0; i < gsc->num_clocks; i++) {
ret = clk_prepare_enable(gsc->clock[i]);
if (ret) {
while (--i >= 0)
clk_disable_unprepare(gsc->clock[i]);
return ret;
}
}
gsc_hw_set_sw_reset(gsc);
gsc_wait_reset(gsc);
gsc_m2m_resume(gsc);
return gsc_m2m_resume(gsc);
return 0;
}
static int gsc_runtime_suspend(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
int ret = 0;
int i;
ret = gsc_m2m_suspend(gsc);
if (!ret)
clk_disable(gsc->clock);
if (ret)
return ret;
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
for (i = gsc->num_clocks - 1; i >= 0; i--)
clk_disable_unprepare(gsc->clock[i]);
pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
return ret;
}
static int gsc_resume(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
unsigned long flags;
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
/* Do not resume if the device was idle before system suspend */
spin_lock_irqsave(&gsc->slock, flags);
if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
!gsc_m2m_opened(gsc)) {
spin_unlock_irqrestore(&gsc->slock, flags);
return 0;
}
spin_unlock_irqrestore(&gsc->slock, flags);
if (!pm_runtime_suspended(dev))
return gsc_runtime_resume(dev);
return 0;
}
static int gsc_suspend(struct device *dev)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state);
if (test_and_set_bit(ST_SUSPEND, &gsc->state))
return 0;
if (!pm_runtime_suspended(dev))
return gsc_runtime_suspend(dev);
return 0;
}
#endif
static const struct dev_pm_ops gsc_pm_ops = {
.suspend = gsc_suspend,
.resume = gsc_resume,
.runtime_suspend = gsc_runtime_suspend,
.runtime_resume = gsc_runtime_resume,
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
};
static struct platform_driver gsc_driver = {

View File

@@ -33,6 +33,7 @@
#define GSC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
#define GSC_MAX_DEVS 4
#define GSC_MAX_CLOCKS 4
#define GSC_M2M_BUF_NUM 0
#define GSC_MAX_CTRL_NUM 10
#define GSC_SC_ALIGN_4 4
@@ -48,9 +49,6 @@
#define GSC_CTX_ABORT (1 << 7)
enum gsc_dev_flags {
/* for global */
ST_SUSPEND,
/* for m2m node */
ST_M2M_OPEN,
ST_M2M_RUN,
@@ -306,12 +304,12 @@ struct gsc_variant {
* struct gsc_driverdata - per device type driver data for init time.
*
* @variant: the variant information for this driver.
* @lclk_frequency: G-Scaler clock frequency
* @num_entities: the number of g-scalers
*/
struct gsc_driverdata {
struct gsc_variant *variant[GSC_MAX_DEVS];
unsigned long lclk_frequency;
const char *clk_names[GSC_MAX_CLOCKS];
int num_clocks;
int num_entities;
};
@@ -335,7 +333,8 @@ struct gsc_dev {
struct platform_device *pdev;
struct gsc_variant *variant;
u16 id;
struct clk *clock;
int num_clocks;
struct clk *clock[GSC_MAX_CLOCKS];
void __iomem *regs;
wait_queue_head_t irq_queue;
struct gsc_m2m_device m2m;

View File

@@ -66,12 +66,29 @@ static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
return ret > 0 ? 0 : ret;
}
static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx)
{
struct vb2_v4l2_buffer *src_vb, *dst_vb;
while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) {
src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
}
while (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) {
dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
}
}
static void gsc_m2m_stop_streaming(struct vb2_queue *q)
{
struct gsc_ctx *ctx = q->drv_priv;
__gsc_m2m_job_abort(ctx);
__gsc_m2m_cleanup_queue(ctx);
pm_runtime_put(&ctx->gsc_dev->pdev->dev);
}
@@ -365,14 +382,8 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh,
max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
gsc->variant->in_buf_cnt : gsc->variant->out_buf_cnt;
if (reqbufs->count > max_cnt) {
if (reqbufs->count > max_cnt)
return -EINVAL;
} else if (reqbufs->count == 0) {
if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
gsc_ctx_state_lock_clear(GSC_SRC_FMT, ctx);
else
gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx);
}
return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
}
@@ -664,8 +675,8 @@ static int gsc_m2m_open(struct file *file)
error_ctrls:
gsc_ctrls_delete(ctx);
error_fh:
v4l2_fh_del(&ctx->fh);
error_fh:
v4l2_fh_exit(&ctx->fh);
kfree(ctx);
unlock:
@@ -766,30 +777,29 @@ int gsc_register_m2m_device(struct gsc_dev *gsc)
gsc->m2m.m2m_dev = v4l2_m2m_init(&gsc_m2m_ops);
if (IS_ERR(gsc->m2m.m2m_dev)) {
dev_err(&pdev->dev, "failed to initialize v4l2-m2m device\n");
ret = PTR_ERR(gsc->m2m.m2m_dev);
goto err_m2m_r1;
return PTR_ERR(gsc->m2m.m2m_dev);
}
ret = video_register_device(&gsc->vdev, VFL_TYPE_GRABBER, -1);
if (ret) {
dev_err(&pdev->dev,
"%s(): failed to register video device\n", __func__);
goto err_m2m_r2;
goto err_m2m_release;
}
pr_debug("gsc m2m driver registered as /dev/video%d", gsc->vdev.num);
return 0;
err_m2m_r2:
err_m2m_release:
v4l2_m2m_release(gsc->m2m.m2m_dev);
err_m2m_r1:
video_device_release(gsc->m2m.vfd);
return ret;
}
void gsc_unregister_m2m_device(struct gsc_dev *gsc)
{
if (gsc)
if (gsc) {
v4l2_m2m_release(gsc->m2m.m2m_dev);
video_unregister_device(&gsc->vdev);
}
}