Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { };
vmmc-supply = <&wl_on_reg>;
sd-uhs-ddr50;
non-removable;
cap-power-off-card;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { };
vmmc-supply = <&wl_on_reg>;
sd-uhs-ddr50;
non-removable;
cap-power-off-card;
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
Expand Down
7 changes: 4 additions & 3 deletions arch/arm64/configs/bcm2712_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_16K_PAGES=y
CONFIG_ARM64_VA_BITS_47=y
CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
CONFIG_NUMA=y
CONFIG_COMPAT=y
CONFIG_ARMV8_DEPRECATED=y
Expand All @@ -59,9 +58,11 @@ CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
CONFIG_RANDOMIZE_BASE=y
CONFIG_CMDLINE="console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
# CONFIG_SUSPEND is not set
CONFIG_PM=y
CONFIG_HIBERNATION=y
CONFIG_PM_DEBUG=y
CONFIG_DPM_WATCHDOG=y
CONFIG_DPM_WATCHDOG_TIMEOUT=30
CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT=5
CONFIG_CPU_IDLE=y
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_STAT=y
Expand Down
12 changes: 10 additions & 2 deletions drivers/gpio/gpio-brcmstb.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/string_choices.h>

enum gio_reg_index {
Expand Down Expand Up @@ -576,8 +577,15 @@ static int brcmstb_gpio_resume(struct device *dev)
#endif /* CONFIG_PM_SLEEP */

static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
.suspend_noirq = brcmstb_gpio_suspend,
.resume_noirq = brcmstb_gpio_resume,
/*
* A hibernate power cycle wipes this GPIO bank's registers, same
* as a suspend-to-RAM transition. Only wiring .suspend_noirq/
* .resume_noirq left the save/restore logic below unreachable on
* the freeze/thaw and poweroff/restore phases hibernate actually
* uses, so an output pin's level (and anything else save/restore
* covers) was silently lost across hibernate specifically.
*/
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(brcmstb_gpio_suspend, brcmstb_gpio_resume)
};

static int brcmstb_gpio_probe(struct platform_device *pdev)
Expand Down
17 changes: 17 additions & 0 deletions drivers/gpu/drm/vc4/vc4_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,22 @@ static void vc4_platform_drm_shutdown(struct platform_device *pdev)
drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
}

static int vc4_drm_suspend(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);

return drm_mode_config_helper_suspend(drm);
}

static int vc4_drm_resume(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);

return drm_mode_config_helper_resume(drm);
}

static DEFINE_SIMPLE_DEV_PM_OPS(vc4_drm_pm_ops, vc4_drm_suspend, vc4_drm_resume);

static const struct of_device_id vc4_of_match[] = {
{ .compatible = "brcm,bcm2711-vc5", .data = (void *)VC4_GEN_5 },
/* NB GEN_6_C will be corrected on D0 hw to GEN_6_D via vc4_hvs_bind */
Expand All @@ -511,6 +527,7 @@ static struct platform_driver vc4_platform_driver = {
.driver = {
.name = "vc4-drm",
.of_match_table = vc4_of_match,
.pm = pm_sleep_ptr(&vc4_drm_pm_ops),
},
};

Expand Down
18 changes: 7 additions & 11 deletions drivers/gpu/drm/vc4/vc4_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -3091,19 +3091,13 @@ static int vc4_hdmi_runtime_resume(struct device *dev)
return ret;

/*
* Whenever the RaspberryPi boots without an HDMI monitor
* plugged in, the firmware won't have initialized the HSM clock
* rate and it will be reported as 0.
*
* If we try to access a register of the controller in such a
* case, it will lead to a silent CPU stall. Let's make sure we
* prevent such a case.
* The clock rate may be reported wrong after suspend to RAM.
* This may cause a cpu stall.
*/
rate = clk_get_rate(vc4_hdmi->hsm_clock);
if (!rate) {
ret = -EINVAL;
goto err_disable_clk;
}
if (!rate)
dev_warn(&vc4_hdmi->pdev->dev,
"hsm_clock rate is 0, proceeding anyway\n");

ret = clk_prepare_enable(vc4_hdmi->audio_clock);
if (ret)
Expand Down Expand Up @@ -3441,6 +3435,8 @@ static const struct dev_pm_ops vc4_hdmi_pm_ops = {
SET_RUNTIME_PM_OPS(vc4_hdmi_runtime_suspend,
vc4_hdmi_runtime_resume,
NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};

struct platform_driver vc4_hdmi_driver = {
Expand Down
64 changes: 52 additions & 12 deletions drivers/gpu/drm/vc4/vc4_hvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/platform_device.h>
#include <linux/pm.h>

#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
Expand Down Expand Up @@ -437,12 +438,28 @@ static const u32 nearest_neighbour_kernel[] =
VC4_LINEAR_PHASE_KERNEL(0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 255, 255, 255, 255);

static void vc4_hvs_write_linear_kernel(struct vc4_hvs *hvs,
struct drm_mm_node *space,
const u32 *kernel)
{
u32 __iomem *dst_kernel = hvs->dlist + space->start;
unsigned int i;

for (i = 0; i < VC4_KERNEL_DWORDS; i++) {
if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS)
writel(kernel[i], &dst_kernel[i]);
else {
writel(kernel[VC4_KERNEL_DWORDS - i - 1],
&dst_kernel[i]);
}
}
}

static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
struct drm_mm_node *space,
const u32 *kernel)
{
int ret, i;
u32 __iomem *dst_kernel;
int ret;

/*
* NOTE: We don't need a call to drm_dev_enter()/drm_dev_exit()
Expand All @@ -456,16 +473,7 @@ static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
return ret;
}

dst_kernel = hvs->dlist + space->start;

for (i = 0; i < VC4_KERNEL_DWORDS; i++) {
if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS)
writel(kernel[i], &dst_kernel[i]);
else {
writel(kernel[VC4_KERNEL_DWORDS - i - 1],
&dst_kernel[i]);
}
}
vc4_hvs_write_linear_kernel(hvs, space, kernel);

return 0;
}
Expand Down Expand Up @@ -2109,6 +2117,8 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hvs))
return PTR_ERR(hvs);

platform_set_drvdata(pdev, hvs);

hvs->regset.base = hvs->regs;

if (vc4->gen == VC4_GEN_6_C) {
Expand Down Expand Up @@ -2291,6 +2301,35 @@ static void vc4_hvs_dev_remove(struct platform_device *pdev)
component_del(&pdev->dev, &vc4_hvs_ops);
}

static int vc4_hvs_resume_early(struct device *dev)
{
struct vc4_hvs *hvs = platform_get_drvdata(to_platform_device(dev));
struct vc4_dev *vc4;
int ret;

if (!hvs)
return 0;

vc4 = hvs->vc4;
if (vc4->gen >= VC4_GEN_6_C)
ret = vc6_hvs_hw_init(hvs);
else
ret = vc4_hvs_hw_init(hvs);
if (ret)
return ret;

vc4_hvs_write_linear_kernel(hvs, &hvs->mitchell_netravali_filter,
mitchell_netravali_1_3_1_3_kernel);
vc4_hvs_write_linear_kernel(hvs, &hvs->nearest_neighbour_filter,
nearest_neighbour_kernel);

return vc4_hvs_cob_init(hvs);
}

static const struct dev_pm_ops vc4_hvs_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, vc4_hvs_resume_early)
};

static const struct of_device_id vc4_hvs_dt_match[] = {
{ .compatible = "brcm,bcm2711-hvs" },
{ .compatible = "brcm,bcm2712-hvs" },
Expand All @@ -2304,5 +2343,6 @@ struct platform_driver vc4_hvs_driver = {
.driver = {
.name = "vc4_hvs",
.of_match_table = vc4_hvs_dt_match,
.pm = pm_sleep_ptr(&vc4_hvs_pm_ops),
},
};
47 changes: 38 additions & 9 deletions drivers/iommu/bcm2712-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/minmax.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/spinlock.h>

#define MMU_WR(off, val) writel(val, mmu->reg_base + (off))
Expand Down Expand Up @@ -207,18 +208,25 @@ static int bcm2712_iommu_init(struct bcm2712_iommu *mmu)
* the aperture does not start from zero), and of the default page.
* For simplicity, both these regions are whole Linux pages.
*/
u = bcm2712_iommu_get_page(mmu, &mmu->top_table);
if (!u)
return -ENOMEM;
if (mmu->top_table) {
u = (u32)(virt_to_phys(mmu->top_table) >> IOMMU_PAGE_SHIFT);
} else {
u = bcm2712_iommu_get_page(mmu, &mmu->top_table);
if (!u)
return -ENOMEM;
}
MMU_WR(MMMU_PT_PA_BASE_OFFSET,
u - ((mmu->aperture_base - mmu->dma_iova_offset) >> L1_AP_BASE_SHIFT));
u = bcm2712_iommu_get_page(mmu, &mmu->default_page);
if (!u) {
bcm2712_iommu_free_page(mmu, mmu->top_table);
return -ENOMEM;
if (mmu->default_page) {
u = (u32)(virt_to_phys(mmu->default_page) >> IOMMU_PAGE_SHIFT);
} else {
u = bcm2712_iommu_get_page(mmu, &mmu->default_page);
if (!u) {
bcm2712_iommu_free_page(mmu, mmu->top_table);
return -ENOMEM;
}
}
MMU_WR(MMMU_ILLEGAL_ADR_OFFSET, MMMU_ILLEGAL_ADR_ENABLE + u);
mmu->nmapped_pages = 0;

/* Flush (and enable) the shared TLB cache; enable this MMU. */
if (mmu->cache)
Expand Down Expand Up @@ -744,6 +752,26 @@ static void bcm2712_iommu_remove(struct platform_device *pdev)
MMU_WR(MMMU_CTRL_OFFSET, 0); /* disable the MMU */
}

static int bcm2712_iommu_suspend(struct device *dev)
{
struct bcm2712_iommu *mmu = dev_get_drvdata(dev);

if (mmu->reg_base)
MMU_WR(MMMU_CTRL_OFFSET, 0); /* disable the MMU */

return 0;
}

static int bcm2712_iommu_resume(struct device *dev)
{
struct bcm2712_iommu *mmu = dev_get_drvdata(dev);

return bcm2712_iommu_init(mmu);
}

static DEFINE_SIMPLE_DEV_PM_OPS(bcm2712_iommu_pm_ops, bcm2712_iommu_suspend,
bcm2712_iommu_resume);

static const struct of_device_id bcm2712_iommu_of_match[] = {
{
. compatible = "brcm,bcm2712-iommu"
Expand All @@ -756,7 +784,8 @@ static struct platform_driver bcm2712_iommu_driver = {
.remove = bcm2712_iommu_remove,
.driver = {
.name = "bcm2712-iommu",
.of_match_table = bcm2712_iommu_of_match
.of_match_table = bcm2712_iommu_of_match,
.pm = pm_sleep_ptr(&bcm2712_iommu_pm_ops),
},
};

Expand Down
40 changes: 30 additions & 10 deletions drivers/irqchip/irq-bcm2712-mip.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm.h>

#include <linux/irqchip/irq-msi-lib.h>

Expand Down Expand Up @@ -170,6 +171,19 @@ static const struct msi_parent_ops mip_msi_parent_ops = {
.init_dev_msi_info = msi_lib_init_dev_msi_info,
};

static void mip_hw_init(struct mip_priv *mip)
{
/*
* All MSI-X unmasked for the host, masked for the VPU, and edge-triggered.
*/
writel(0, mip->base + MIP_INT_MASKL_HOST);
writel(0, mip->base + MIP_INT_MASKH_HOST);
writel(~0, mip->base + MIP_INT_MASKL_VPU);
writel(~0, mip->base + MIP_INT_MASKH_VPU);
writel(~0, mip->base + MIP_INT_CFGL_HOST);
writel(~0, mip->base + MIP_INT_CFGH_HOST);
}

static int mip_init_domains(struct mip_priv *mip, struct device_node *np)
{
struct irq_domain_info info = {
Expand All @@ -184,15 +198,7 @@ static int mip_init_domains(struct mip_priv *mip, struct device_node *np)
if (!msi_create_parent_irq_domain(&info, &mip_msi_parent_ops))
return -ENOMEM;

/*
* All MSI-X unmasked for the host, masked for the VPU, and edge-triggered.
*/
writel(0, mip->base + MIP_INT_MASKL_HOST);
writel(0, mip->base + MIP_INT_MASKH_HOST);
writel(~0, mip->base + MIP_INT_MASKL_VPU);
writel(~0, mip->base + MIP_INT_MASKH_VPU);
writel(~0, mip->base + MIP_INT_CFGL_HOST);
writel(~0, mip->base + MIP_INT_CFGH_HOST);
mip_hw_init(mip);

return 0;
}
Expand Down Expand Up @@ -244,6 +250,7 @@ static int mip_msi_probe(struct platform_device *pdev, struct device_node *paren

spin_lock_init(&mip->lock);
mip->dev = &pdev->dev;
platform_set_drvdata(pdev, mip);

ret = mip_parse_dt(mip, node);
if (ret)
Expand Down Expand Up @@ -279,9 +286,22 @@ static int mip_msi_probe(struct platform_device *pdev, struct device_node *paren
return ret;
}

static int mip_resume(struct device *dev)
{
struct mip_priv *mip = dev_get_drvdata(dev);

mip_hw_init(mip);

return 0;
}

static const struct dev_pm_ops mip_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, mip_resume)
};

IRQCHIP_PLATFORM_DRIVER_BEGIN(mip_msi)
IRQCHIP_MATCH("brcm,bcm2712-mip", mip_msi_probe)
IRQCHIP_PLATFORM_DRIVER_END(mip_msi)
IRQCHIP_PLATFORM_DRIVER_END(mip_msi, .pm = &mip_pm_ops)
MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller");
MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
MODULE_AUTHOR("Stanimir Varbanov <svarbanov@suse.de>");
Expand Down
Loading