Commit 2f6f8af6 authored by Robert Foss's avatar Robert Foss Committed by Mauro Carvalho Chehab
Browse files

media: camss: Refactor VFE power domain toggling



For Titan ISPs clocks fail to re-enable during vfe_get()
after any vfe has been halted and its corresponding power
domain power has been detached.

Since all of the clocks depend on all of the PDs, per
VFE PD detaching is no option for Gen2 HW.

In order to not have regressions on for Gen1 HW, refactor
the power domain management into hardware version specific
code paths.

Signed-off-by: default avatarRobert Foss <robert.foss@linaro.org>
Reviewed-by: default avatarAndrey Konovalov <andrey.konovalov@linaro.org>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 2f8b6719
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -695,6 +695,24 @@ static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
	spin_unlock_irqrestore(&vfe->output_lock, flags);
}

/*
 * vfe_pm_domain_off - Disable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static void vfe_pm_domain_off(struct vfe_device *vfe)
{
	/* nop */
}

/*
 * vfe_pm_domain_on - Enable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static int vfe_pm_domain_on(struct vfe_device *vfe)
{
	return 0;
}

/*
 * vfe_queue_buffer - Add empty buffer
 * @vid: Video device structure
@@ -756,6 +774,8 @@ const struct vfe_hw_ops vfe_ops_170 = {
	.hw_version_read = vfe_hw_version_read,
	.isr_read = vfe_isr_read,
	.isr = vfe_isr,
	.pm_domain_off = vfe_pm_domain_off,
	.pm_domain_on = vfe_pm_domain_on,
	.reg_update_clear = vfe_reg_update_clear,
	.reg_update = vfe_reg_update,
	.subdev_init = vfe_subdev_init,
+20 −0
Original line number Diff line number Diff line
@@ -938,6 +938,24 @@ static irqreturn_t vfe_isr(int irq, void *dev)
	return IRQ_HANDLED;
}

/*
 * vfe_pm_domain_off - Disable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static void vfe_pm_domain_off(struct vfe_device *vfe)
{
	/* nop */
}

/*
 * vfe_pm_domain_on - Enable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static int vfe_pm_domain_on(struct vfe_device *vfe)
{
	return 0;
}

static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = {
	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
@@ -989,6 +1007,8 @@ const struct vfe_hw_ops vfe_ops_4_1 = {
	.hw_version_read = vfe_hw_version_read,
	.isr_read = vfe_isr_read,
	.isr = vfe_isr,
	.pm_domain_off = vfe_pm_domain_off,
	.pm_domain_on = vfe_pm_domain_on,
	.reg_update_clear = vfe_reg_update_clear,
	.reg_update = vfe_reg_update,
	.subdev_init = vfe_subdev_init,
+39 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * Copyright (C) 2015-2018 Linaro Ltd.
 */

#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -1104,6 +1105,42 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
}

/*
 * vfe_pm_domain_off - Disable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static void vfe_pm_domain_off(struct vfe_device *vfe)
{
	struct camss *camss;

	if (!vfe)
		return;

	camss = vfe->camss;

	device_link_del(camss->genpd_link[vfe->id]);
}

/*
 * vfe_pm_domain_on - Enable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static int vfe_pm_domain_on(struct vfe_device *vfe)
{
	struct camss *camss = vfe->camss;
	enum vfe_line_id id = vfe->id;

	camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS |
						DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);

	if (!camss->genpd_link[id]) {
		dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id);
		return -EINVAL;
	}

	return 0;
}

static void vfe_violation_read(struct vfe_device *vfe)
{
	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
@@ -1162,6 +1199,8 @@ const struct vfe_hw_ops vfe_ops_4_7 = {
	.hw_version_read = vfe_hw_version_read,
	.isr_read = vfe_isr_read,
	.isr = vfe_isr,
	.pm_domain_off = vfe_pm_domain_off,
	.pm_domain_on = vfe_pm_domain_on,
	.reg_update_clear = vfe_reg_update_clear,
	.reg_update = vfe_reg_update,
	.subdev_init = vfe_subdev_init,
+34 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * Copyright (C) 2015-2021 Linaro Ltd.
 */

#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -1093,6 +1094,37 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
}

/*
 * vfe_pm_domain_off - Disable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static void vfe_pm_domain_off(struct vfe_device *vfe)
{
	struct camss *camss = vfe->camss;

	device_link_del(camss->genpd_link[vfe->id]);
}

/*
 * vfe_pm_domain_on - Enable power domains specific to this VFE.
 * @vfe: VFE Device
 */
static int vfe_pm_domain_on(struct vfe_device *vfe)
{
	struct camss *camss = vfe->camss;
	enum vfe_line_id id = vfe->id;

	camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS |
						DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);

	if (!camss->genpd_link[id]) {
		dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id);
		return -EINVAL;
	}

	return 0;
}

static void vfe_violation_read(struct vfe_device *vfe)
{
	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
@@ -1151,6 +1183,8 @@ const struct vfe_hw_ops vfe_ops_4_8 = {
	.hw_version_read = vfe_hw_version_read,
	.isr_read = vfe_isr_read,
	.isr = vfe_isr,
	.pm_domain_off = vfe_pm_domain_off,
	.pm_domain_on = vfe_pm_domain_on,
	.reg_update_clear = vfe_reg_update_clear,
	.reg_update = vfe_reg_update,
	.subdev_init = vfe_subdev_init,
+3 −3
Original line number Diff line number Diff line
@@ -580,7 +580,7 @@ static int vfe_get(struct vfe_device *vfe)
	mutex_lock(&vfe->power_lock);

	if (vfe->power_count == 0) {
		ret = camss_pm_domain_on(vfe->camss, vfe->id);
		ret = vfe->ops->pm_domain_on(vfe);
		if (ret < 0)
			goto error_pm_domain;

@@ -620,7 +620,7 @@ static int vfe_get(struct vfe_device *vfe)

error_pm_runtime_get:
	pm_runtime_put_sync(vfe->camss->dev);
	camss_pm_domain_off(vfe->camss, vfe->id);
	vfe->ops->pm_domain_off(vfe);

error_pm_domain:
	mutex_unlock(&vfe->power_lock);
@@ -646,7 +646,7 @@ static void vfe_put(struct vfe_device *vfe)
		}
		camss_disable_clocks(vfe->nclocks, vfe->clock);
		pm_runtime_put_sync(vfe->camss->dev);
		camss_pm_domain_off(vfe->camss, vfe->id);
		vfe->ops->pm_domain_off(vfe);
	}

	vfe->power_count--;
Loading