Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: camss: Split power domain management

There are three cases of power domain management on supported platforms:
1) CAMSS on MSM8916, where a single VFE power domain is operated outside
of the camss device driver,
2) CAMSS on MSM8996 and SDM630/SDM660, where two VFE power domains are
managed separately by the camss device driver, the power domains are
linked and unlinked on demand by their functions vfe_pm_domain_on()
and vfe_pm_domain_off() respectively,
3) CAMSS on SDM845 and SM8250 platforms, and there are two VFE power
domains and their parent power domain TITAN_TOP, the latter one
shall be turned on prior to turning on any of VFE power domains.

Due to a previously missing link between TITAN_TOP and VFEx power domains
in the latter case, which is now fixed by [1], it was decided always to
turn on all found VFE power domains and TITAN_TOP power domain, even if
just one particular VFE is needed to be enabled or none of VFE power
domains are required, for instance the latter case is when vfe_lite is in
use. This misusage becomes more incovenient and clumsy, if next generations
are to be supported, for instance CAMSS on SM8450 has three VFE power
domains.

The change splits the power management support for platforms with TITAN_TOP
parent power domain, and, since 'power-domain-names' property is not
present in camss device tree nodes, the assumption is that the first
N power domains from the 'power-domains' list correspond to VFE power
domains, and, if the number of power domains is greater than number of
non-lite VFEs, then the last power domain from the list is the TITAN_TOP
power domain.

Signed-off-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
Reviewed-by: Robert Foss <robert.foss@linaro.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Vladimir Zapolskiy and committed by
Mauro Carvalho Chehab
46cc0317 be11096d

+54 -16
+19 -1
drivers/media/platform/qcom/camss/camss-vfe-170.c
··· 687 687 */ 688 688 static void vfe_pm_domain_off(struct vfe_device *vfe) 689 689 { 690 - /* nop */ 690 + struct camss *camss = vfe->camss; 691 + 692 + if (vfe->id >= camss->vfe_num) 693 + return; 694 + 695 + device_link_del(camss->genpd_link[vfe->id]); 691 696 } 692 697 693 698 /* ··· 701 696 */ 702 697 static int vfe_pm_domain_on(struct vfe_device *vfe) 703 698 { 699 + struct camss *camss = vfe->camss; 700 + enum vfe_line_id id = vfe->id; 701 + 702 + if (id >= camss->vfe_num) 703 + return 0; 704 + 705 + camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], 706 + DL_FLAG_STATELESS | 707 + DL_FLAG_PM_RUNTIME | 708 + DL_FLAG_RPM_ACTIVE); 709 + if (!camss->genpd_link[id]) 710 + return -EINVAL; 711 + 704 712 return 0; 705 713 } 706 714
+19 -1
drivers/media/platform/qcom/camss/camss-vfe-480.c
··· 494 494 */ 495 495 static void vfe_pm_domain_off(struct vfe_device *vfe) 496 496 { 497 - /* nop */ 497 + struct camss *camss = vfe->camss; 498 + 499 + if (vfe->id >= camss->vfe_num) 500 + return; 501 + 502 + device_link_del(camss->genpd_link[vfe->id]); 498 503 } 499 504 500 505 /* ··· 508 503 */ 509 504 static int vfe_pm_domain_on(struct vfe_device *vfe) 510 505 { 506 + struct camss *camss = vfe->camss; 507 + enum vfe_line_id id = vfe->id; 508 + 509 + if (id >= camss->vfe_num) 510 + return 0; 511 + 512 + camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], 513 + DL_FLAG_STATELESS | 514 + DL_FLAG_PM_RUNTIME | 515 + DL_FLAG_RPM_ACTIVE); 516 + if (!camss->genpd_link[id]) 517 + return -EINVAL; 518 + 511 519 return 0; 512 520 } 513 521
+16 -14
drivers/media/platform/qcom/camss/camss.c
··· 1453 1453 static int camss_configure_pd(struct camss *camss) 1454 1454 { 1455 1455 struct device *dev = camss->dev; 1456 - int last_pm_domain = 0; 1457 1456 int i; 1458 1457 int ret; 1459 1458 ··· 1483 1484 if (!camss->genpd_link) 1484 1485 return -ENOMEM; 1485 1486 1487 + /* 1488 + * VFE power domains are in the beginning of the list, and while all 1489 + * power domains should be attached, only if TITAN_TOP power domain is 1490 + * found in the list, it should be linked over here. 1491 + */ 1486 1492 for (i = 0; i < camss->genpd_num; i++) { 1487 1493 camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); 1488 1494 if (IS_ERR(camss->genpd[i])) { 1489 1495 ret = PTR_ERR(camss->genpd[i]); 1490 1496 goto fail_pm; 1491 1497 } 1498 + } 1492 1499 1493 - camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i], 1494 - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | 1495 - DL_FLAG_RPM_ACTIVE); 1496 - if (!camss->genpd_link[i]) { 1497 - dev_pm_domain_detach(camss->genpd[i], true); 1500 + if (i > camss->vfe_num) { 1501 + camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1], 1502 + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | 1503 + DL_FLAG_RPM_ACTIVE); 1504 + if (!camss->genpd_link[i - 1]) { 1498 1505 ret = -EINVAL; 1499 1506 goto fail_pm; 1500 1507 } 1501 - 1502 - last_pm_domain = i; 1503 1508 } 1504 1509 1505 1510 return 0; 1506 1511 1507 1512 fail_pm: 1508 - for (i = 0; i < last_pm_domain; i++) { 1509 - device_link_del(camss->genpd_link[i]); 1513 + for (--i ; i >= 0; i--) 1510 1514 dev_pm_domain_detach(camss->genpd[i], true); 1511 - } 1512 1515 1513 1516 return ret; 1514 1517 } ··· 1712 1711 if (camss->genpd_num == 1) 1713 1712 return; 1714 1713 1715 - for (i = 0; i < camss->genpd_num; i++) { 1716 - device_link_del(camss->genpd_link[i]); 1714 + if (camss->genpd_num > camss->vfe_num) 1715 + device_link_del(camss->genpd_link[camss->genpd_num - 1]); 1716 + 1717 + for (i = 0; i < camss->genpd_num; i++) 1717 1718 dev_pm_domain_detach(camss->genpd[i], true); 1718 - } 1719 1719 } 1720 1720 1721 1721 /*