Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ properties:
items:
- const: aon

resets:
maxItems: 1

reset-names:
items:
- const: gpu-clkgen

"#power-domain-cells":
const: 1

Expand Down
9 changes: 8 additions & 1 deletion Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ properties:
# work with newer dts.
- const: img,img-axe
- const: img,img-rogue
- items:
- enum:
- thead,th1520-gpu
- const: img,img-bxm-4-64
- const: img,img-rogue
- items:
- enum:
- ti,j721s2-gpu
Expand Down Expand Up @@ -93,7 +98,9 @@ allOf:
properties:
compatible:
contains:
const: img,img-axe-1-16m
enum:
- img,img-axe-1-16m
- img,img-bxm-4-64
then:
properties:
power-domains:
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -21393,6 +21393,7 @@ F: drivers/mailbox/mailbox-th1520.c
F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
F: drivers/pinctrl/pinctrl-th1520.c
F: drivers/pmdomain/thead/
F: drivers/power/sequencing/pwrseq-thead-gpu.c
F: drivers/reset/reset-th1520.c
F: include/dt-bindings/clock/thead,th1520-clk-ap.h
F: include/dt-bindings/power/thead,th1520-power.h
Expand Down
25 changes: 25 additions & 0 deletions arch/riscv/boot/dts/thead/th1520.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/thead,th1520-clk-ap.h>
#include <dt-bindings/power/thead,th1520-power.h>
#include <dt-bindings/reset/thead,th1520-reset.h>

/ {
compatible = "thead,th1520";
Expand Down Expand Up @@ -224,6 +225,13 @@
#clock-cells = <0>;
};

gpu_mem_clk: mem-clk {
compatible = "fixed-clock";
clock-frequency = <0>;
clock-output-names = "gpu_mem_clk";
#clock-cells = <0>;
};

stmmac_axi_config: stmmac-axi-config {
snps,wr_osr_lmt = <15>;
snps,rd_osr_lmt = <15>;
Expand All @@ -234,6 +242,8 @@
compatible = "thead,th1520-aon";
mboxes = <&mbox_910t 1>;
mbox-names = "aon";
resets = <&rst TH1520_RESET_ID_GPU_CLKGEN>;
reset-names = "gpu-clkgen";
#power-domain-cells = <1>;
};

Expand Down Expand Up @@ -497,6 +507,21 @@
#clock-cells = <1>;
};

gpu: gpu@ffef400000 {
compatible = "thead,th1520-gpu", "img,img-bxm-4-64",
"img,img-rogue";
reg = <0xff 0xef400000 0x0 0x100000>;
interrupt-parent = <&plic>;
interrupts = <102 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_vo CLK_GPU_CORE>,
<&gpu_mem_clk>,
<&clk_vo CLK_GPU_CFG_ACLK>;
clock-names = "core", "mem", "sys";
power-domains = <&aon TH1520_GPU_PD>;
power-domain-names = "a";
resets = <&rst TH1520_RESET_ID_GPU>;
};

rst: reset-controller@ffef528000 {
compatible = "thead,th1520-reset";
reg = <0xff 0xef528000 0x0 0x4f>;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/imagination/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

config DRM_POWERVR
tristate "Imagination Technologies PowerVR (Series 6 and later) & IMG Graphics"
depends on ARM64
depends on (ARM64 || RISCV)
depends on DRM
depends on PM
select DRM_EXEC
select DRM_GEM_SHMEM_HELPER
select DRM_SCHED
select DRM_GPUVM
select FW_LOADER
select POWER_SEQUENCING
help
Choose this option if you have a system that has an Imagination
Technologies PowerVR (Series 6 or later) or IMG GPU.
Expand Down
31 changes: 27 additions & 4 deletions drivers/gpu/drm/imagination/pvr_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
#include <linux/firmware.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pwrseq/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/stddef.h>
Expand Down Expand Up @@ -618,6 +620,9 @@ pvr_device_init(struct pvr_device *pvr_dev)
struct device *dev = drm_dev->dev;
int err;

/* Get the platform-specific data based on the compatible string. */
pvr_dev->soc_data = of_device_get_match_data(dev);

/*
* Setup device parameters. We do this first in case other steps
* depend on them.
Expand All @@ -631,10 +636,28 @@ pvr_device_init(struct pvr_device *pvr_dev)
if (err)
return err;

/* Get the reset line for the GPU */
err = pvr_device_reset_init(pvr_dev);
if (err)
return err;
/*
* For platforms that require it, get the power sequencer.
* For all others, perform manual reset initialization.
*/
if (pvr_dev->soc_data && pvr_dev->soc_data->has_pwrseq) {
pvr_dev->pwrseq = devm_pwrseq_get(dev, "gpu-power");
if (IS_ERR(pvr_dev->pwrseq)) {
/*
* This platform requires a sequencer. If we can't get
* it, we must return the error (including -EPROBE_DEFER
* to wait for the provider to appear)
*/
return dev_err_probe(
dev, PTR_ERR(pvr_dev->pwrseq),
"Failed to get required power sequencer\n");
}
} else {
/* This platform does not use a sequencer, init reset manually. */
err = pvr_device_reset_init(pvr_dev);
if (err)
return err;
}

/* Explicitly power the GPU so we can access control registers before the FW is booted. */
err = pm_runtime_resume_and_get(dev);
Expand Down
17 changes: 17 additions & 0 deletions drivers/gpu/drm/imagination/pvr_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ struct clk;
/* Forward declaration from <linux/firmware.h>. */
struct firmware;

/* Forward declaration from <linux/pwrseq/consumer.h */
struct pwrseq_desc;

/**
* struct pvr_gpu_id - Hardware GPU ID information for a PowerVR device
* @b: Branch ID.
Expand All @@ -57,6 +60,14 @@ struct pvr_fw_version {
u16 major, minor;
};

/*
* struct pvr_soc_data - Platform specific data associated with a compatible string.
* @has_pwrseq: True if the platform requires power management via the pwrseq framework.
*/
struct pvr_soc_data {
bool has_pwrseq;
};

/**
* struct pvr_device - powervr-specific wrapper for &struct drm_device
*/
Expand Down Expand Up @@ -98,6 +109,9 @@ struct pvr_device {
/** @fw_version: Firmware version detected at runtime. */
struct pvr_fw_version fw_version;

/** @soc_data: Pointer to platform-specific quirk data. */
const struct pvr_soc_data *soc_data;

/** @regs_resource: Resource representing device control registers. */
struct resource *regs_resource;

Expand Down Expand Up @@ -148,6 +162,9 @@ struct pvr_device {
*/
struct reset_control *reset;

/** @pwrseq: Pointer to a power sequencer, if one is used. */
struct pwrseq_desc *pwrseq;

/** @irq: IRQ number. */
int irq;

Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/imagination/pvr_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,11 @@ static void pvr_remove(struct platform_device *plat_dev)
}

static const struct of_device_id dt_match[] = {
{
.compatible = "thead,th1520-gpu",
.data = &(struct pvr_soc_data){ .has_pwrseq = true },
},

{ .compatible = "img,img-rogue", .data = NULL },

/*
Expand Down Expand Up @@ -1513,4 +1518,5 @@ MODULE_DESCRIPTION(PVR_DRIVER_DESC);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_IMPORT_NS("DMA_BUF");
MODULE_FIRMWARE("powervr/rogue_33.15.11.3_v1.fw");
MODULE_FIRMWARE("powervr/rogue_36.52.104.182_v1.fw");
MODULE_FIRMWARE("powervr/rogue_36.53.104.796_v1.fw");
82 changes: 53 additions & 29 deletions drivers/gpu/drm/imagination/pvr_power.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pwrseq/consumer.h>
#include <linux/reset.h>
#include <linux/timer.h>
#include <linux/types.h>
Expand Down Expand Up @@ -234,6 +235,19 @@ pvr_watchdog_init(struct pvr_device *pvr_dev)
return 0;
}

static int pvr_power_off_sequence_manual(struct pvr_device *pvr_dev)
{
int err;

err = reset_control_assert(pvr_dev->reset);

clk_disable_unprepare(pvr_dev->mem_clk);
clk_disable_unprepare(pvr_dev->sys_clk);
clk_disable_unprepare(pvr_dev->core_clk);

return err;
}

int
pvr_power_device_suspend(struct device *dev)
{
Expand All @@ -252,11 +266,10 @@ pvr_power_device_suspend(struct device *dev)
goto err_drm_dev_exit;
}

clk_disable_unprepare(pvr_dev->mem_clk);
clk_disable_unprepare(pvr_dev->sys_clk);
clk_disable_unprepare(pvr_dev->core_clk);

err = reset_control_assert(pvr_dev->reset);
if (pvr_dev->pwrseq)
err = pwrseq_power_off(pvr_dev->pwrseq);
else
err = pvr_power_off_sequence_manual(pvr_dev);

err_drm_dev_exit:
drm_dev_exit(idx);
Expand All @@ -276,44 +289,55 @@ pvr_power_device_resume(struct device *dev)
if (!drm_dev_enter(drm_dev, &idx))
return -EIO;

err = clk_prepare_enable(pvr_dev->core_clk);
if (err)
goto err_drm_dev_exit;
if (pvr_dev->pwrseq) {
err = pwrseq_power_on(pvr_dev->pwrseq);
if (err)
goto err_drm_dev_exit;
} else {
err = clk_prepare_enable(pvr_dev->core_clk);
if (err)
goto err_drm_dev_exit;

err = clk_prepare_enable(pvr_dev->sys_clk);
if (err)
goto err_core_clk_disable;
err = clk_prepare_enable(pvr_dev->sys_clk);
if (err)
goto err_core_clk_disable;

err = clk_prepare_enable(pvr_dev->mem_clk);
if (err)
goto err_sys_clk_disable;
err = clk_prepare_enable(pvr_dev->mem_clk);
if (err)
goto err_sys_clk_disable;

/*
* According to the hardware manual, a delay of at least 32 clock
* cycles is required between de-asserting the clkgen reset and
* de-asserting the GPU reset. Assuming a worst-case scenario with
* a very high GPU clock frequency, a delay of 1 microsecond is
* sufficient to ensure this requirement is met across all
* feasible GPU clock speeds.
*/
udelay(1);
/*
* According to the hardware manual, a delay of at least 32 clock
* cycles is required between de-asserting the clkgen reset and
* de-asserting the GPU reset. Assuming a worst-case scenario with
* a very high GPU clock frequency, a delay of 1 microsecond is
* sufficient to ensure this requirement is met across all
* feasible GPU clock speeds.
*/
udelay(1);

err = reset_control_deassert(pvr_dev->reset);
if (err)
goto err_mem_clk_disable;
err = reset_control_deassert(pvr_dev->reset);
if (err)
goto err_mem_clk_disable;
}

if (pvr_dev->fw_dev.booted) {
err = pvr_power_fw_enable(pvr_dev);
if (err)
goto err_reset_assert;
goto err_power_off;
}

drm_dev_exit(idx);

return 0;

err_reset_assert:
reset_control_assert(pvr_dev->reset);
err_power_off:
if (pvr_dev->pwrseq)
pwrseq_power_off(pvr_dev->pwrseq);
else
pvr_power_off_sequence_manual(pvr_dev);

goto err_drm_dev_exit;

err_mem_clk_disable:
clk_disable_unprepare(pvr_dev->mem_clk);
Expand Down
1 change: 1 addition & 0 deletions drivers/pmdomain/thead/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config TH1520_PM_DOMAINS
tristate "Support TH1520 Power Domains"
depends on TH1520_AON_PROTOCOL
select REGMAP_MMIO
select AUXILIARY_BUS
help
This driver enables power domain management for the T-HEAD
TH-1520 SoC. On this SoC there are number of power domains,
Expand Down
Loading
Loading