Skip to content

Commit

Permalink
media: camss: Refactor VFE power domain toggling
Browse files Browse the repository at this point in the history
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: Robert Foss <robert.foss@linaro.org>
Reviewed-by: Andrey Konovalov <andrey.konovalov@linaro.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
  • Loading branch information
robertfoss authored and mchehab committed Mar 22, 2021
1 parent 2f8b671 commit 2f6f8af
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 36 deletions.
20 changes: 20 additions & 0 deletions drivers/media/platform/qcom/camss/camss-vfe-170.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions drivers/media/platform/qcom/camss/camss-vfe-4-1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
39 changes: 39 additions & 0 deletions drivers/media/platform/qcom/camss/camss-vfe-4-7.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
34 changes: 34 additions & 0 deletions drivers/media/platform/qcom/camss/camss-vfe-4-8.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions drivers/media/platform/qcom/camss/camss-vfe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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--;
Expand Down
2 changes: 2 additions & 0 deletions drivers/media/platform/qcom/camss/camss-vfe.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ struct vfe_hw_ops {
void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
irqreturn_t (*isr)(int irq, void *dev);
void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
void (*pm_domain_off)(struct vfe_device *vfe);
int (*pm_domain_on)(struct vfe_device *vfe);
void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id);
void (*reg_update_clear)(struct vfe_device *vfe,
enum vfe_line_id line_id);
Expand Down
93 changes: 65 additions & 28 deletions drivers/media/platform/qcom/camss/camss.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,24 +799,24 @@ int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock)

int camss_pm_domain_on(struct camss *camss, int id)
{
if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
camss->genpd_link[id] = device_link_add(camss->dev,
camss->genpd[id], DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
int ret = 0;

if (id < camss->vfe_num) {
struct vfe_device *vfe = &camss->vfe[id];

if (!camss->genpd_link[id])
return -EINVAL;
ret = vfe->ops->pm_domain_on(vfe);
}

return 0;
return ret;
}

void camss_pm_domain_off(struct camss *camss, int id)
{
if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660)
device_link_del(camss->genpd_link[id]);
if (id < camss->vfe_num) {
struct vfe_device *vfe = &camss->vfe[id];

vfe->ops->pm_domain_off(vfe);
}
}

/*
Expand Down Expand Up @@ -1234,6 +1234,47 @@ static const struct media_device_ops camss_media_ops = {
.link_notify = v4l2_pipeline_link_notify,
};

static int camss_configure_pd(struct camss *camss)
{
int nbr_pm_domains = 0;
int last_pm_domain = 0;
int i;
int ret;

if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660)
nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;

for (i = 0; i < nbr_pm_domains; i++) {
camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
if (IS_ERR(camss->genpd[i])) {
ret = PTR_ERR(camss->genpd[i]);
goto fail_pm;
}

camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i],
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
if (!camss->genpd_link[i]) {
dev_pm_domain_detach(camss->genpd[i], true);
ret = -EINVAL;
goto fail_pm;
}

last_pm_domain = i;
}

return 0;

fail_pm:
for (i = 0; i < last_pm_domain; i++) {
device_link_del(camss->genpd_link[i]);
dev_pm_domain_detach(camss->genpd[i], true);
}

return ret;
}

/*
* camss_probe - Probe CAMSS platform device
* @pdev: Pointer to CAMSS platform device
Expand Down Expand Up @@ -1366,20 +1407,10 @@ static int camss_probe(struct platform_device *pdev)
}
}

if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
camss->dev, PM_DOMAIN_VFE0);
if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
return PTR_ERR(camss->genpd[PM_DOMAIN_VFE0]);

camss->genpd[PM_DOMAIN_VFE1] = dev_pm_domain_attach_by_id(
camss->dev, PM_DOMAIN_VFE1);
if (IS_ERR(camss->genpd[PM_DOMAIN_VFE1])) {
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0],
true);
return PTR_ERR(camss->genpd[PM_DOMAIN_VFE1]);
}
ret = camss_configure_pd(camss);
if (ret < 0) {
dev_err(dev, "Failed to configure power domains: %d\n", ret);
return ret;
}

pm_runtime_enable(dev);
Expand All @@ -1400,16 +1431,22 @@ static int camss_probe(struct platform_device *pdev)

void camss_delete(struct camss *camss)
{
int nbr_pm_domains = 0;
int i;

v4l2_device_unregister(&camss->v4l2_dev);
media_device_unregister(&camss->media_dev);
media_device_cleanup(&camss->media_dev);

pm_runtime_disable(camss->dev);

if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
camss->version == CAMSS_660)
nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;

for (i = 0; i < nbr_pm_domains; i++) {
device_link_del(camss->genpd_link[i]);
dev_pm_domain_detach(camss->genpd[i], true);
}

kfree(camss);
Expand Down
10 changes: 5 additions & 5 deletions drivers/media/platform/qcom/camss/camss.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ struct resources_ispif {
};

enum pm_domain {
PM_DOMAIN_VFE0,
PM_DOMAIN_VFE1,
PM_DOMAIN_COUNT
PM_DOMAIN_VFE0 = 0,
PM_DOMAIN_VFE1 = 1,
PM_DOMAIN_GEN1_COUNT = 2, /* CAMSS series of ISPs */
};

enum camss_version {
Expand All @@ -83,8 +83,8 @@ struct camss {
int vfe_num;
struct vfe_device *vfe;
atomic_t ref_count;
struct device *genpd[PM_DOMAIN_COUNT];
struct device_link *genpd_link[PM_DOMAIN_COUNT];
struct device *genpd[PM_DOMAIN_GEN1_COUNT];
struct device_link *genpd_link[PM_DOMAIN_GEN1_COUNT];
};

struct camss_camera_interface {
Expand Down

0 comments on commit 2f6f8af

Please sign in to comment.