mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 09:44:18 +08:00
Merge branch 'imx/soc' into imx/dt
This commit is contained in:
commit
40cb1981b3
59
Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
Normal file
59
Documentation/devicetree/bindings/power/fsl,imx-gpc.txt
Normal file
@ -0,0 +1,59 @@
|
||||
Freescale i.MX General Power Controller
|
||||
=======================================
|
||||
|
||||
The i.MX6Q General Power Control (GPC) block contains DVFS load tracking
|
||||
counters and Power Gating Control (PGC) for the CPU and PU (GPU/VPU) power
|
||||
domains.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx6q-gpc" or "fsl,imx6sl-gpc"
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
- interrupts: Should contain GPC interrupt request 1
|
||||
- pu-supply: Link to the LDO regulator powering the PU power domain
|
||||
- clocks: Clock phandles to devices in the PU power domain that need
|
||||
to be enabled during domain power-up for reset propagation.
|
||||
- #power-domain-cells: Should be 1, see below:
|
||||
|
||||
The gpc node is a power-controller as documented by the generic power domain
|
||||
bindings in Documentation/devicetree/bindings/power/power_domain.txt.
|
||||
|
||||
Example:
|
||||
|
||||
gpc: gpc@020dc000 {
|
||||
compatible = "fsl,imx6q-gpc";
|
||||
reg = <0x020dc000 0x4000>;
|
||||
interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 90 IRQ_TYPE_LEVEL_HIGH>;
|
||||
pu-supply = <®_pu>;
|
||||
clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>,
|
||||
<&clks IMX6QDL_CLK_GPU3D_SHADER>,
|
||||
<&clks IMX6QDL_CLK_GPU2D_CORE>,
|
||||
<&clks IMX6QDL_CLK_GPU2D_AXI>,
|
||||
<&clks IMX6QDL_CLK_OPENVG_AXI>,
|
||||
<&clks IMX6QDL_CLK_VPU_AXI>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
|
||||
Specifying power domain for IP modules
|
||||
======================================
|
||||
|
||||
IP cores belonging to a power domain should contain a 'power-domains' property
|
||||
that is a phandle pointing to the gpc device node and a DOMAIN_INDEX specifying
|
||||
the power domain the device belongs to.
|
||||
|
||||
Example of a device that is part of the PU power domain:
|
||||
|
||||
vpu: vpu@02040000 {
|
||||
reg = <0x02040000 0x3c000>;
|
||||
/* ... */
|
||||
power-domains = <&gpc 1>;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
The following DOMAIN_INDEX values are valid for i.MX6Q:
|
||||
ARM_DOMAIN 0
|
||||
PU_DOMAIN 1
|
||||
The following additional DOMAIN_INDEX value is valid for i.MX6SL:
|
||||
DISPLAY_DOMAIN 2
|
@ -21,6 +21,7 @@ config MXC_AVIC
|
||||
|
||||
config MXC_DEBUG_BOARD
|
||||
bool "Enable MXC debug board(for 3-stack)"
|
||||
depends on MACH_MX27_3DS || MACH_MX31_3DS || MACH_MX35_3DS
|
||||
help
|
||||
The debug board is an integral part of the MXC 3-stack(PDK)
|
||||
platforms, it can be attached or removed from the peripheral
|
||||
@ -50,6 +51,7 @@ config HAVE_IMX_ANATOP
|
||||
|
||||
config HAVE_IMX_GPC
|
||||
bool
|
||||
select PM_GENERIC_DOMAINS if PM
|
||||
|
||||
config HAVE_IMX_MMDC
|
||||
bool
|
||||
@ -585,6 +587,7 @@ config SOC_VF610
|
||||
select ARM_GIC
|
||||
select PINCTRL_VF610
|
||||
select PL310_ERRATA_769419 if CACHE_L2X0
|
||||
select SMP_ON_UP if SMP
|
||||
|
||||
help
|
||||
This enables support for Freescale Vybrid VF610 processor.
|
||||
|
@ -119,6 +119,7 @@ static unsigned int share_count_asrc;
|
||||
static unsigned int share_count_ssi1;
|
||||
static unsigned int share_count_ssi2;
|
||||
static unsigned int share_count_ssi3;
|
||||
static unsigned int share_count_mipi_core_cfg;
|
||||
|
||||
static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
@ -246,6 +247,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
||||
clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
|
||||
clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2);
|
||||
clk[IMX6QDL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
|
||||
clk[IMX6QDL_CLK_VIDEO_27M] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
|
||||
if (cpu_is_imx6dl()) {
|
||||
clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
|
||||
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
|
||||
@ -400,7 +402,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
||||
clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
|
||||
clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26);
|
||||
clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0);
|
||||
clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4);
|
||||
clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4);
|
||||
clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6);
|
||||
clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8);
|
||||
clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10);
|
||||
@ -415,7 +417,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
|
||||
clk[IMX6QDL_CLK_LDB_DI0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12);
|
||||
clk[IMX6QDL_CLK_LDB_DI1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14);
|
||||
clk[IMX6QDL_CLK_IPU2_DI1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10);
|
||||
clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16);
|
||||
clk[IMX6QDL_CLK_HSI_TX] = imx_clk_gate2_shared("hsi_tx", "hsi_tx_podf", base + 0x74, 16, &share_count_mipi_core_cfg);
|
||||
clk[IMX6QDL_CLK_MIPI_CORE_CFG] = imx_clk_gate2_shared("mipi_core_cfg", "video_27m", base + 0x74, 16, &share_count_mipi_core_cfg);
|
||||
clk[IMX6QDL_CLK_MIPI_IPG] = imx_clk_gate2_shared("mipi_ipg", "ipg", base + 0x74, 16, &share_count_mipi_core_cfg);
|
||||
if (cpu_is_imx6dl())
|
||||
/*
|
||||
* The multiplexer and divider of the imx6q clock gpu2d get
|
||||
|
@ -10,15 +10,25 @@
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include "common.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#define GPC_CNTR 0x000
|
||||
#define GPC_IMR1 0x008
|
||||
#define GPC_PGC_GPU_PDN 0x260
|
||||
#define GPC_PGC_GPU_PUPSCR 0x264
|
||||
#define GPC_PGC_GPU_PDNSCR 0x268
|
||||
#define GPC_PGC_CPU_PDN 0x2a0
|
||||
#define GPC_PGC_CPU_PUPSCR 0x2a4
|
||||
#define GPC_PGC_CPU_PDNSCR 0x2a8
|
||||
@ -27,6 +37,18 @@
|
||||
|
||||
#define IMR_NUM 4
|
||||
|
||||
#define GPU_VPU_PUP_REQ BIT(1)
|
||||
#define GPU_VPU_PDN_REQ BIT(0)
|
||||
|
||||
#define GPC_CLK_MAX 6
|
||||
|
||||
struct pu_domain {
|
||||
struct generic_pm_domain base;
|
||||
struct regulator *reg;
|
||||
struct clk *clk[GPC_CLK_MAX];
|
||||
int num_clks;
|
||||
};
|
||||
|
||||
static void __iomem *gpc_base;
|
||||
static u32 gpc_wake_irqs[IMR_NUM];
|
||||
static u32 gpc_saved_imrs[IMR_NUM];
|
||||
@ -170,3 +192,194 @@ void __init imx_gpc_init(void)
|
||||
gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
|
||||
gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS
|
||||
|
||||
static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
|
||||
{
|
||||
int iso, iso2sw;
|
||||
u32 val;
|
||||
|
||||
/* Read ISO and ISO2SW power down delays */
|
||||
val = readl_relaxed(gpc_base + GPC_PGC_GPU_PDNSCR);
|
||||
iso = val & 0x3f;
|
||||
iso2sw = (val >> 8) & 0x3f;
|
||||
|
||||
/* Gate off PU domain when GPU/VPU when powered down */
|
||||
writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
|
||||
|
||||
/* Request GPC to power down GPU/VPU */
|
||||
val = readl_relaxed(gpc_base + GPC_CNTR);
|
||||
val |= GPU_VPU_PDN_REQ;
|
||||
writel_relaxed(val, gpc_base + GPC_CNTR);
|
||||
|
||||
/* Wait ISO + ISO2SW IPG clock cycles */
|
||||
ndelay((iso + iso2sw) * 1000 / 66);
|
||||
}
|
||||
|
||||
static int imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct pu_domain *pu = container_of(genpd, struct pu_domain, base);
|
||||
|
||||
_imx6q_pm_pu_power_off(genpd);
|
||||
|
||||
if (pu->reg)
|
||||
regulator_disable(pu->reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx6q_pm_pu_power_on(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct pu_domain *pu = container_of(genpd, struct pu_domain, base);
|
||||
int i, ret, sw, sw2iso;
|
||||
u32 val;
|
||||
|
||||
if (pu->reg)
|
||||
ret = regulator_enable(pu->reg);
|
||||
if (pu->reg && ret) {
|
||||
pr_err("%s: failed to enable regulator: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable reset clocks for all devices in the PU domain */
|
||||
for (i = 0; i < pu->num_clks; i++)
|
||||
clk_prepare_enable(pu->clk[i]);
|
||||
|
||||
/* Gate off PU domain when GPU/VPU when powered down */
|
||||
writel_relaxed(0x1, gpc_base + GPC_PGC_GPU_PDN);
|
||||
|
||||
/* Read ISO and ISO2SW power down delays */
|
||||
val = readl_relaxed(gpc_base + GPC_PGC_GPU_PUPSCR);
|
||||
sw = val & 0x3f;
|
||||
sw2iso = (val >> 8) & 0x3f;
|
||||
|
||||
/* Request GPC to power up GPU/VPU */
|
||||
val = readl_relaxed(gpc_base + GPC_CNTR);
|
||||
val |= GPU_VPU_PUP_REQ;
|
||||
writel_relaxed(val, gpc_base + GPC_CNTR);
|
||||
|
||||
/* Wait ISO + ISO2SW IPG clock cycles */
|
||||
ndelay((sw + sw2iso) * 1000 / 66);
|
||||
|
||||
/* Disable reset clocks for all devices in the PU domain */
|
||||
for (i = 0; i < pu->num_clks; i++)
|
||||
clk_disable_unprepare(pu->clk[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct generic_pm_domain imx6q_arm_domain = {
|
||||
.name = "ARM",
|
||||
};
|
||||
|
||||
static struct pu_domain imx6q_pu_domain = {
|
||||
.base = {
|
||||
.name = "PU",
|
||||
.power_off = imx6q_pm_pu_power_off,
|
||||
.power_on = imx6q_pm_pu_power_on,
|
||||
.power_off_latency_ns = 25000,
|
||||
.power_on_latency_ns = 2000000,
|
||||
},
|
||||
};
|
||||
|
||||
static struct generic_pm_domain imx6sl_display_domain = {
|
||||
.name = "DISPLAY",
|
||||
};
|
||||
|
||||
static struct generic_pm_domain *imx_gpc_domains[] = {
|
||||
&imx6q_arm_domain,
|
||||
&imx6q_pu_domain.base,
|
||||
&imx6sl_display_domain,
|
||||
};
|
||||
|
||||
static struct genpd_onecell_data imx_gpc_onecell_data = {
|
||||
.domains = imx_gpc_domains,
|
||||
.num_domains = ARRAY_SIZE(imx_gpc_domains),
|
||||
};
|
||||
|
||||
static int imx_gpc_genpd_init(struct device *dev, struct regulator *pu_reg)
|
||||
{
|
||||
struct clk *clk;
|
||||
bool is_off;
|
||||
int i;
|
||||
|
||||
imx6q_pu_domain.reg = pu_reg;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
clk = of_clk_get(dev->of_node, i);
|
||||
if (IS_ERR(clk))
|
||||
break;
|
||||
if (i >= GPC_CLK_MAX) {
|
||||
dev_err(dev, "more than %d clocks\n", GPC_CLK_MAX);
|
||||
goto clk_err;
|
||||
}
|
||||
imx6q_pu_domain.clk[i] = clk;
|
||||
}
|
||||
imx6q_pu_domain.num_clks = i;
|
||||
|
||||
is_off = IS_ENABLED(CONFIG_PM);
|
||||
if (is_off) {
|
||||
_imx6q_pm_pu_power_off(&imx6q_pu_domain.base);
|
||||
} else {
|
||||
/*
|
||||
* Enable power if compiled without CONFIG_PM in case the
|
||||
* bootloader disabled it.
|
||||
*/
|
||||
imx6q_pm_pu_power_on(&imx6q_pu_domain.base);
|
||||
}
|
||||
|
||||
pm_genpd_init(&imx6q_pu_domain.base, NULL, is_off);
|
||||
return of_genpd_add_provider_onecell(dev->of_node,
|
||||
&imx_gpc_onecell_data);
|
||||
|
||||
clk_err:
|
||||
while (i--)
|
||||
clk_put(imx6q_pu_domain.clk[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int imx_gpc_genpd_init(struct device *dev, struct regulator *reg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_GENERIC_DOMAINS */
|
||||
|
||||
static int imx_gpc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct regulator *pu_reg;
|
||||
int ret;
|
||||
|
||||
pu_reg = devm_regulator_get_optional(&pdev->dev, "pu");
|
||||
if (PTR_ERR(pu_reg) == -ENODEV)
|
||||
pu_reg = NULL;
|
||||
if (IS_ERR(pu_reg)) {
|
||||
ret = PTR_ERR(pu_reg);
|
||||
dev_err(&pdev->dev, "failed to get pu regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return imx_gpc_genpd_init(&pdev->dev, pu_reg);
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_gpc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-gpc" },
|
||||
{ .compatible = "fsl,imx6sl-gpc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver imx_gpc_driver = {
|
||||
.driver = {
|
||||
.name = "imx-gpc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = imx_gpc_dt_ids,
|
||||
},
|
||||
.probe = imx_gpc_probe,
|
||||
};
|
||||
|
||||
static int __init imx_pgc_init(void)
|
||||
{
|
||||
return platform_driver_register(&imx_gpc_driver);
|
||||
}
|
||||
subsys_initcall(imx_pgc_init);
|
||||
|
@ -142,7 +142,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
|
||||
&pdev->dev);
|
||||
const struct imx_weim_devtype *devtype = of_id->data;
|
||||
struct device_node *child;
|
||||
int ret;
|
||||
int ret, have_child = 0;
|
||||
|
||||
if (devtype == &imx50_weim_devtype) {
|
||||
ret = imx_weim_gpr_setup(pdev);
|
||||
@ -155,14 +155,15 @@ static int __init weim_parse_dt(struct platform_device *pdev,
|
||||
continue;
|
||||
|
||||
ret = weim_timing_setup(child, base, devtype);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s set timing failed.\n",
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "%s set timing failed.\n",
|
||||
child->full_name);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
have_child = 1;
|
||||
}
|
||||
|
||||
ret = of_platform_populate(pdev->dev.of_node,
|
||||
if (have_child)
|
||||
ret = of_platform_populate(pdev->dev.of_node,
|
||||
of_default_bus_match_table,
|
||||
NULL, &pdev->dev);
|
||||
if (ret)
|
||||
|
@ -248,6 +248,9 @@
|
||||
#define IMX6QDL_PLL6_BYPASS 235
|
||||
#define IMX6QDL_PLL7_BYPASS 236
|
||||
#define IMX6QDL_CLK_GPT_3M 237
|
||||
#define IMX6QDL_CLK_END 238
|
||||
#define IMX6QDL_CLK_VIDEO_27M 238
|
||||
#define IMX6QDL_CLK_MIPI_CORE_CFG 239
|
||||
#define IMX6QDL_CLK_MIPI_IPG 240
|
||||
#define IMX6QDL_CLK_END 241
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */
|
||||
|
@ -207,6 +207,7 @@
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0 (0x2 << 6)
|
||||
#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1 (0x3 << 6)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_SHIFT 4
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_MASK (0x3 << 4)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0 (0x0 << 4)
|
||||
#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4)
|
||||
|
Loading…
Reference in New Issue
Block a user