mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
ARM: SoC driver updates
Misc driver updates for platforms, many of them power related.
- Rockchip adds power domain support for rk3066 and rk3188
- Amlogic adds a power measurement driver
- Allwinner adds SRAM support for three platforms (F1C100, H5, A64 C1)
- Wakeup and ti-sysc (platform bus) fixes for OMAP/DRA7
- Broadcom fixes suspend/resume with Thumb2 kernels, and improves
stability of a handful of firmware/platform interfaces
- PXA completes their conversion to dmaengine framework
- Renesas does a bunch of PM cleanups across many platforms
- Tegra adds support for suspend/resume on T186/T194, which includes
some driver cleanups and addition of wake events
- Tegra also adds a driver for memory controller (EMC) on Tegra2
- i.MX tweaks power domain bindings, and adds support for i.MX8MQ in GPC
- Atmel adds identifiers and LPDDR2 support for a new SoC, SAM9X60
+ misc cleanups across several platforms
-----BEGIN PGP SIGNATURE-----
iQJDBAABCAAtFiEElf+HevZ4QCAJmMQ+jBrnPN6EHHcFAlwqd4APHG9sb2ZAbGl4
b20ubmV0AAoJEIwa5zzehBx3HXoP/icWJTGrbf9R6T7r0RWB3xeV8ouTPMM8YM5C
6wD4LkkjgZ16Hz/ellJ0Oug77LdnJ/ZI7jH2u0IcKRXr4sL94hEo11jAJLLtCHpt
rGiItMuEDMhNFcAK/yREI6FtRqjNZhsTuR+gkcjzMnGLCaTA1+RwQNdugH0hh0fF
z8C6tjN+fRIeS0wInBzR/402GcgRU0DIJrr0kmklS0u6tc2QW24ffv8ymvMiVO46
l8VemmdxVZsBU2iehraPy6mSXsyTm04dNTuHnrIw3nE3kTJF7jMvpqI/euU1eZl6
6EzrrCym8nC66IlqhHMBB427PK8sRqJTqwqSXO6e90AqiK4H2bMovXKiob/Psq+e
yWqPOrAr8YBLqTgauvCzVm/xneT5rZM4N0BYhOk172Uk52qenNWDnqHj41A4CMSM
/id3L1cHs5nf2qwuMncXvLX+Y2vO2n6cMmF8cDRLu592OBZRcVepUM0xoaSdZScv
LJsP3jH3RRcY3L2rf7bY2Mitp48bDgZMZdw/viSHsFS+SVr225uNFALFDQ9kNEoZ
2d9i9IvC7xOMhdVAX03U7DuRcpKXBPcv+arA57PiVvR4M1HeU7VvD4ayP5loVX2J
GoDIKiPQitAsOKzyPyZ5Jw04lxio3xZbrbmmVzEH8uKWIV5omdiMnSrFsEfduRCT
rU+Mqe2j
=yEX2
-----END PGP SIGNATURE-----
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Olof Johansson:
"Misc driver updates for platforms, many of them power related.
- Rockchip adds power domain support for rk3066 and rk3188
- Amlogic adds a power measurement driver
- Allwinner adds SRAM support for three platforms (F1C100, H5, A64
C1)
- Wakeup and ti-sysc (platform bus) fixes for OMAP/DRA7
- Broadcom fixes suspend/resume with Thumb2 kernels, and improves
stability of a handful of firmware/platform interfaces
- PXA completes their conversion to dmaengine framework
- Renesas does a bunch of PM cleanups across many platforms
- Tegra adds support for suspend/resume on T186/T194, which includes
some driver cleanups and addition of wake events
- Tegra also adds a driver for memory controller (EMC) on Tegra2
- i.MX tweaks power domain bindings, and adds support for i.MX8MQ in
GPC
- Atmel adds identifiers and LPDDR2 support for a new SoC, SAM9X60
and misc cleanups across several platforms"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (73 commits)
ARM: at91: add support in soc driver for new SAM9X60
ARM: at91: add support in soc driver for LPDDR2 SiP
memory: omap-gpmc: Use of_node_name_eq for node name comparisons
bus: ti-sysc: Check for no-reset and no-idle flags at the child level
ARM: OMAP2+: Check also the first dts child for hwmod flags
soc: amlogic: meson-clk-measure: Add missing REGMAP_MMIO dependency
soc: imx: gpc: Increase GPC_CLK_MAX to 7
soc: renesas: rcar-sysc: Fix power domain control after system resume
soc: renesas: rcar-sysc: Merge PM Domain registration and linking
soc: renesas: rcar-sysc: Remove rcar_sysc_power_{down,up}() helpers
soc: renesas: r8a77990-sysc: Fix initialization order of 3DG-{A,B}
dt-bindings: sram: sunxi: Add compatible for the A64 SRAM C1
dt-bindings: sram: sunxi: Add bindings for the H5 with SRAM C1
dt-bindings: sram: Add Allwinner suniv F1C100s
soc: sunxi: sram: Add support for the H5 SoC system control
soc: sunxi: sram: Enable EMAC clock access for H3 variant
soc: imx: gpcv2: add support for i.MX8MQ SoC
soc: imx: gpcv2: move register access table to domain data
soc: imx: gpcv2: prefix i.MX7 specific defines
dmaengine: pxa: make the filter function internal
...
This commit is contained in:
commit
d36377c6eb
68 changed files with 3910 additions and 668 deletions
|
|
@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_GEMINI) += gemini/
|
|||
obj-$(CONFIG_ARCH_MXC) += imx/
|
||||
obj-$(CONFIG_SOC_XWAY) += lantiq/
|
||||
obj-y += mediatek/
|
||||
obj-$(CONFIG_ARCH_MESON) += amlogic/
|
||||
obj-y += amlogic/
|
||||
obj-y += qcom/
|
||||
obj-y += renesas/
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
|
|
|
|||
|
|
@ -7,6 +7,15 @@ config MESON_CANVAS
|
|||
help
|
||||
Say yes to support the canvas IP for Amlogic SoCs.
|
||||
|
||||
config MESON_CLK_MEASURE
|
||||
bool "Amlogic Meson SoC Clock Measure driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
default ARCH_MESON
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Say yes to support of Measuring a set of internal SoC clocks
|
||||
from the debugfs interface.
|
||||
|
||||
config MESON_GX_SOCINFO
|
||||
bool "Amlogic Meson GX SoC Information driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
|
||||
obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o
|
||||
obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
|
||||
obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
|
||||
obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
|
||||
|
|
|
|||
350
drivers/soc/amlogic/meson-clk-measure.c
Normal file
350
drivers/soc/amlogic/meson-clk-measure.c
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2018 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*/
|
||||
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MSR_CLK_DUTY 0x0
|
||||
#define MSR_CLK_REG0 0x4
|
||||
#define MSR_CLK_REG1 0x8
|
||||
#define MSR_CLK_REG2 0xc
|
||||
|
||||
#define MSR_DURATION GENMASK(15, 0)
|
||||
#define MSR_ENABLE BIT(16)
|
||||
#define MSR_CONT BIT(17) /* continuous measurement */
|
||||
#define MSR_INTR BIT(18) /* interrupts */
|
||||
#define MSR_RUN BIT(19)
|
||||
#define MSR_CLK_SRC GENMASK(26, 20)
|
||||
#define MSR_BUSY BIT(31)
|
||||
|
||||
#define MSR_VAL_MASK GENMASK(15, 0)
|
||||
|
||||
#define DIV_MIN 32
|
||||
#define DIV_STEP 32
|
||||
#define DIV_MAX 640
|
||||
|
||||
#define CLK_MSR_MAX 128
|
||||
|
||||
struct meson_msr_id {
|
||||
struct meson_msr *priv;
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct meson_msr {
|
||||
struct regmap *regmap;
|
||||
struct meson_msr_id msr_table[CLK_MSR_MAX];
|
||||
};
|
||||
|
||||
#define CLK_MSR_ID(__id, __name) \
|
||||
[__id] = {.id = __id, .name = __name,}
|
||||
|
||||
static struct meson_msr_id clk_msr_m8[CLK_MSR_MAX] = {
|
||||
CLK_MSR_ID(0, "ring_osc_out_ee0"),
|
||||
CLK_MSR_ID(1, "ring_osc_out_ee1"),
|
||||
CLK_MSR_ID(2, "ring_osc_out_ee2"),
|
||||
CLK_MSR_ID(3, "a9_ring_osck"),
|
||||
CLK_MSR_ID(6, "vid_pll"),
|
||||
CLK_MSR_ID(7, "clk81"),
|
||||
CLK_MSR_ID(8, "encp"),
|
||||
CLK_MSR_ID(9, "encl"),
|
||||
CLK_MSR_ID(11, "eth_rmii"),
|
||||
CLK_MSR_ID(13, "amclk"),
|
||||
CLK_MSR_ID(14, "fec_clk_0"),
|
||||
CLK_MSR_ID(15, "fec_clk_1"),
|
||||
CLK_MSR_ID(16, "fec_clk_2"),
|
||||
CLK_MSR_ID(18, "a9_clk_div16"),
|
||||
CLK_MSR_ID(19, "hdmi_sys"),
|
||||
CLK_MSR_ID(20, "rtc_osc_clk_out"),
|
||||
CLK_MSR_ID(21, "i2s_clk_in_src0"),
|
||||
CLK_MSR_ID(22, "clk_rmii_from_pad"),
|
||||
CLK_MSR_ID(23, "hdmi_ch0_tmds"),
|
||||
CLK_MSR_ID(24, "lvds_fifo"),
|
||||
CLK_MSR_ID(26, "sc_clk_int"),
|
||||
CLK_MSR_ID(28, "sar_adc"),
|
||||
CLK_MSR_ID(30, "mpll_clk_test_out"),
|
||||
CLK_MSR_ID(31, "audac_clkpi"),
|
||||
CLK_MSR_ID(32, "vdac"),
|
||||
CLK_MSR_ID(33, "sdhc_rx"),
|
||||
CLK_MSR_ID(34, "sdhc_sd"),
|
||||
CLK_MSR_ID(35, "mali"),
|
||||
CLK_MSR_ID(36, "hdmi_tx_pixel"),
|
||||
CLK_MSR_ID(38, "vdin_meas"),
|
||||
CLK_MSR_ID(39, "pcm_sclk"),
|
||||
CLK_MSR_ID(40, "pcm_mclk"),
|
||||
CLK_MSR_ID(41, "eth_rx_tx"),
|
||||
CLK_MSR_ID(42, "pwm_d"),
|
||||
CLK_MSR_ID(43, "pwm_c"),
|
||||
CLK_MSR_ID(44, "pwm_b"),
|
||||
CLK_MSR_ID(45, "pwm_a"),
|
||||
CLK_MSR_ID(46, "pcm2_sclk"),
|
||||
CLK_MSR_ID(47, "ddr_dpll_pt"),
|
||||
CLK_MSR_ID(48, "pwm_f"),
|
||||
CLK_MSR_ID(49, "pwm_e"),
|
||||
CLK_MSR_ID(59, "hcodec"),
|
||||
CLK_MSR_ID(60, "usb_32k_alt"),
|
||||
CLK_MSR_ID(61, "gpio"),
|
||||
CLK_MSR_ID(62, "vid2_pll"),
|
||||
CLK_MSR_ID(63, "mipi_csi_cfg"),
|
||||
};
|
||||
|
||||
static struct meson_msr_id clk_msr_gx[CLK_MSR_MAX] = {
|
||||
CLK_MSR_ID(0, "ring_osc_out_ee_0"),
|
||||
CLK_MSR_ID(1, "ring_osc_out_ee_1"),
|
||||
CLK_MSR_ID(2, "ring_osc_out_ee_2"),
|
||||
CLK_MSR_ID(3, "a53_ring_osc"),
|
||||
CLK_MSR_ID(4, "gp0_pll"),
|
||||
CLK_MSR_ID(6, "enci"),
|
||||
CLK_MSR_ID(7, "clk81"),
|
||||
CLK_MSR_ID(8, "encp"),
|
||||
CLK_MSR_ID(9, "encl"),
|
||||
CLK_MSR_ID(10, "vdac"),
|
||||
CLK_MSR_ID(11, "rgmii_tx"),
|
||||
CLK_MSR_ID(12, "pdm"),
|
||||
CLK_MSR_ID(13, "amclk"),
|
||||
CLK_MSR_ID(14, "fec_0"),
|
||||
CLK_MSR_ID(15, "fec_1"),
|
||||
CLK_MSR_ID(16, "fec_2"),
|
||||
CLK_MSR_ID(17, "sys_pll_div16"),
|
||||
CLK_MSR_ID(18, "sys_cpu_div16"),
|
||||
CLK_MSR_ID(19, "hdmitx_sys"),
|
||||
CLK_MSR_ID(20, "rtc_osc_out"),
|
||||
CLK_MSR_ID(21, "i2s_in_src0"),
|
||||
CLK_MSR_ID(22, "eth_phy_ref"),
|
||||
CLK_MSR_ID(23, "hdmi_todig"),
|
||||
CLK_MSR_ID(26, "sc_int"),
|
||||
CLK_MSR_ID(28, "sar_adc"),
|
||||
CLK_MSR_ID(31, "mpll_test_out"),
|
||||
CLK_MSR_ID(32, "vdec"),
|
||||
CLK_MSR_ID(35, "mali"),
|
||||
CLK_MSR_ID(36, "hdmi_tx_pixel"),
|
||||
CLK_MSR_ID(37, "i958"),
|
||||
CLK_MSR_ID(38, "vdin_meas"),
|
||||
CLK_MSR_ID(39, "pcm_sclk"),
|
||||
CLK_MSR_ID(40, "pcm_mclk"),
|
||||
CLK_MSR_ID(41, "eth_rx_or_rmii"),
|
||||
CLK_MSR_ID(42, "mp0_out"),
|
||||
CLK_MSR_ID(43, "fclk_div5"),
|
||||
CLK_MSR_ID(44, "pwm_b"),
|
||||
CLK_MSR_ID(45, "pwm_a"),
|
||||
CLK_MSR_ID(46, "vpu"),
|
||||
CLK_MSR_ID(47, "ddr_dpll_pt"),
|
||||
CLK_MSR_ID(48, "mp1_out"),
|
||||
CLK_MSR_ID(49, "mp2_out"),
|
||||
CLK_MSR_ID(50, "mp3_out"),
|
||||
CLK_MSR_ID(51, "nand_core"),
|
||||
CLK_MSR_ID(52, "sd_emmc_b"),
|
||||
CLK_MSR_ID(53, "sd_emmc_a"),
|
||||
CLK_MSR_ID(55, "vid_pll_div_out"),
|
||||
CLK_MSR_ID(56, "cci"),
|
||||
CLK_MSR_ID(57, "wave420l_c"),
|
||||
CLK_MSR_ID(58, "wave420l_b"),
|
||||
CLK_MSR_ID(59, "hcodec"),
|
||||
CLK_MSR_ID(60, "alt_32k"),
|
||||
CLK_MSR_ID(61, "gpio_msr"),
|
||||
CLK_MSR_ID(62, "hevc"),
|
||||
CLK_MSR_ID(66, "vid_lock"),
|
||||
CLK_MSR_ID(70, "pwm_f"),
|
||||
CLK_MSR_ID(71, "pwm_e"),
|
||||
CLK_MSR_ID(72, "pwm_d"),
|
||||
CLK_MSR_ID(73, "pwm_c"),
|
||||
CLK_MSR_ID(75, "aoclkx2_int"),
|
||||
CLK_MSR_ID(76, "aoclk_int"),
|
||||
CLK_MSR_ID(77, "rng_ring_osc_0"),
|
||||
CLK_MSR_ID(78, "rng_ring_osc_1"),
|
||||
CLK_MSR_ID(79, "rng_ring_osc_2"),
|
||||
CLK_MSR_ID(80, "rng_ring_osc_3"),
|
||||
CLK_MSR_ID(81, "vapb"),
|
||||
CLK_MSR_ID(82, "ge2d"),
|
||||
};
|
||||
|
||||
static int meson_measure_id(struct meson_msr_id *clk_msr_id,
|
||||
unsigned int duration)
|
||||
{
|
||||
struct meson_msr *priv = clk_msr_id->priv;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
regmap_write(priv->regmap, MSR_CLK_REG0, 0);
|
||||
|
||||
/* Set measurement duration */
|
||||
regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_DURATION,
|
||||
FIELD_PREP(MSR_DURATION, duration - 1));
|
||||
|
||||
/* Set ID */
|
||||
regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_CLK_SRC,
|
||||
FIELD_PREP(MSR_CLK_SRC, clk_msr_id->id));
|
||||
|
||||
/* Enable & Start */
|
||||
regmap_update_bits(priv->regmap, MSR_CLK_REG0,
|
||||
MSR_RUN | MSR_ENABLE,
|
||||
MSR_RUN | MSR_ENABLE);
|
||||
|
||||
ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0,
|
||||
val, !(val & MSR_BUSY), 10, 10000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable */
|
||||
regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0);
|
||||
|
||||
/* Get the value in multiple of gate time counts */
|
||||
regmap_read(priv->regmap, MSR_CLK_REG2, &val);
|
||||
|
||||
if (val >= MSR_VAL_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
return DIV_ROUND_CLOSEST_ULL((val & MSR_VAL_MASK) * 1000000ULL,
|
||||
duration);
|
||||
}
|
||||
|
||||
static int meson_measure_best_id(struct meson_msr_id *clk_msr_id,
|
||||
unsigned int *precision)
|
||||
{
|
||||
unsigned int duration = DIV_MAX;
|
||||
int ret;
|
||||
|
||||
/* Start from max duration and down to min duration */
|
||||
do {
|
||||
ret = meson_measure_id(clk_msr_id, duration);
|
||||
if (ret >= 0)
|
||||
*precision = (2 * 1000000) / duration;
|
||||
else
|
||||
duration -= DIV_STEP;
|
||||
} while (duration >= DIV_MIN && ret == -EINVAL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int clk_msr_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct meson_msr_id *clk_msr_id = s->private;
|
||||
unsigned int precision = 0;
|
||||
int val;
|
||||
|
||||
val = meson_measure_best_id(clk_msr_id, &precision);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
seq_printf(s, "%d\t+/-%dHz\n", val, precision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(clk_msr);
|
||||
|
||||
static int clk_msr_summary_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct meson_msr_id *msr_table = s->private;
|
||||
unsigned int precision = 0;
|
||||
int val, i;
|
||||
|
||||
seq_puts(s, " clock rate precision\n");
|
||||
seq_puts(s, "---------------------------------------------\n");
|
||||
|
||||
for (i = 0 ; i < CLK_MSR_MAX ; ++i) {
|
||||
if (!msr_table[i].name)
|
||||
continue;
|
||||
|
||||
val = meson_measure_best_id(&msr_table[i], &precision);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
seq_printf(s, " %-20s %10d +/-%dHz\n",
|
||||
msr_table[i].name, val, precision);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(clk_msr_summary);
|
||||
|
||||
static const struct regmap_config meson_clk_msr_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = MSR_CLK_REG2,
|
||||
};
|
||||
|
||||
static int meson_msr_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct meson_msr_id *match_data;
|
||||
struct meson_msr *priv;
|
||||
struct resource *res;
|
||||
struct dentry *root, *clks;
|
||||
void __iomem *base;
|
||||
int i;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct meson_msr),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
match_data = device_get_match_data(&pdev->dev);
|
||||
if (!match_data) {
|
||||
dev_err(&pdev->dev, "failed to get match data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memcpy(priv->msr_table, match_data, sizeof(priv->msr_table));
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base)) {
|
||||
dev_err(&pdev->dev, "io resource mapping failed\n");
|
||||
return PTR_ERR(base);
|
||||
}
|
||||
|
||||
priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&meson_clk_msr_regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
|
||||
root = debugfs_create_dir("meson-clk-msr", NULL);
|
||||
clks = debugfs_create_dir("clks", root);
|
||||
|
||||
debugfs_create_file("measure_summary", 0444, root,
|
||||
priv->msr_table, &clk_msr_summary_fops);
|
||||
|
||||
for (i = 0 ; i < CLK_MSR_MAX ; ++i) {
|
||||
if (!priv->msr_table[i].name)
|
||||
continue;
|
||||
|
||||
priv->msr_table[i].priv = priv;
|
||||
|
||||
debugfs_create_file(priv->msr_table[i].name, 0444, clks,
|
||||
&priv->msr_table[i], &clk_msr_fops);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id meson_msr_match_table[] = {
|
||||
{
|
||||
.compatible = "amlogic,meson-gx-clk-measure",
|
||||
.data = (void *)clk_msr_gx,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson8-clk-measure",
|
||||
.data = (void *)clk_msr_m8,
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson8b-clk-measure",
|
||||
.data = (void *)clk_msr_m8,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver meson_msr_driver = {
|
||||
.probe = meson_msr_probe,
|
||||
.driver = {
|
||||
.name = "meson_msr",
|
||||
.of_match_table = meson_msr_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(meson_msr_driver);
|
||||
|
|
@ -66,6 +66,8 @@ static const struct at91_soc __initconst socs[] = {
|
|||
AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"),
|
||||
AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"),
|
||||
AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"),
|
||||
AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_EXID_MATCH,
|
||||
"sam9x60", "sam9x60"),
|
||||
#endif
|
||||
#ifdef CONFIG_SOC_SAMA5
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH,
|
||||
|
|
@ -90,12 +92,20 @@ static const struct at91_soc __initconst socs[] = {
|
|||
"sama5d27c 128MiB SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_D5M_EXID_MATCH,
|
||||
"sama5d27c 64MiB SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD1G_EXID_MATCH,
|
||||
"sama5d27c 128MiB LPDDR2 SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD2G_EXID_MATCH,
|
||||
"sama5d27c 256MiB LPDDR2 SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH,
|
||||
"sama5d28", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH,
|
||||
"sama5d28", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_D1G_EXID_MATCH,
|
||||
"sama5d28c 128MiB SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD1G_EXID_MATCH,
|
||||
"sama5d28c 128MiB LPDDR2 SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD2G_EXID_MATCH,
|
||||
"sama5d28c 256MiB LPDDR2 SiP", "sama5d2"),
|
||||
AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH,
|
||||
"sama5d31", "sama5d3"),
|
||||
AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ at91_soc_init(const struct at91_soc *socs);
|
|||
#define AT91SAM9G45_CIDR_MATCH 0x019b05a0
|
||||
#define AT91SAM9X5_CIDR_MATCH 0x019a05a0
|
||||
#define AT91SAM9N12_CIDR_MATCH 0x019a07a0
|
||||
#define SAM9X60_CIDR_MATCH 0x019b35a0
|
||||
|
||||
#define AT91SAM9M11_EXID_MATCH 0x00000001
|
||||
#define AT91SAM9M10_EXID_MATCH 0x00000002
|
||||
|
|
@ -58,6 +59,8 @@ at91_soc_init(const struct at91_soc *socs);
|
|||
#define AT91SAM9N12_EXID_MATCH 0x00000006
|
||||
#define AT91SAM9CN11_EXID_MATCH 0x00000009
|
||||
|
||||
#define SAM9X60_EXID_MATCH 0x00000000
|
||||
|
||||
#define AT91SAM9XE128_CIDR_MATCH 0x329973a0
|
||||
#define AT91SAM9XE256_CIDR_MATCH 0x329a93a0
|
||||
#define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0
|
||||
|
|
@ -73,9 +76,13 @@ at91_soc_init(const struct at91_soc *socs);
|
|||
#define SAMA5D26CU_EXID_MATCH 0x00000012
|
||||
#define SAMA5D27C_D1G_EXID_MATCH 0x00000033
|
||||
#define SAMA5D27C_D5M_EXID_MATCH 0x00000032
|
||||
#define SAMA5D27C_LD1G_EXID_MATCH 0x00000061
|
||||
#define SAMA5D27C_LD2G_EXID_MATCH 0x00000062
|
||||
#define SAMA5D27CU_EXID_MATCH 0x00000011
|
||||
#define SAMA5D27CN_EXID_MATCH 0x00000021
|
||||
#define SAMA5D28C_D1G_EXID_MATCH 0x00000013
|
||||
#define SAMA5D28C_LD1G_EXID_MATCH 0x00000071
|
||||
#define SAMA5D28C_LD2G_EXID_MATCH 0x00000072
|
||||
#define SAMA5D28CU_EXID_MATCH 0x00000010
|
||||
#define SAMA5D28CN_EXID_MATCH 0x00000020
|
||||
|
||||
|
|
|
|||
|
|
@ -31,13 +31,17 @@ static const struct of_device_id brcmstb_machine_match[] = {
|
|||
|
||||
bool soc_is_brcmstb(void)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device_node *root;
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
if (!root)
|
||||
return false;
|
||||
|
||||
return of_match_node(brcmstb_machine_match, root) != NULL;
|
||||
match = of_match_node(brcmstb_machine_match, root);
|
||||
of_node_put(root);
|
||||
|
||||
return match != NULL;
|
||||
}
|
||||
|
||||
u32 brcmstb_get_family_id(void)
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ noinline int brcmstb_pm_s3_finish(void)
|
|||
{
|
||||
struct brcmstb_s3_params *params = ctrl.s3_params;
|
||||
dma_addr_t params_pa = ctrl.s3_params_pa;
|
||||
phys_addr_t reentry = virt_to_phys(&cpu_resume);
|
||||
phys_addr_t reentry = virt_to_phys(&cpu_resume_arm);
|
||||
enum bsp_initiate_command cmd;
|
||||
u32 flags;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* (C) 2015 Pengutronix, Alexander Aring <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Aring <aar@pengutronix.de>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
menu "i.MX SoC drivers"
|
||||
|
||||
config IMX7_PM_DOMAINS
|
||||
bool "i.MX7 PM domains"
|
||||
depends on SOC_IMX7D || (COMPILE_TEST && OF)
|
||||
config IMX_GPCV2_PM_DOMAINS
|
||||
bool "i.MX GPCv2 PM domains"
|
||||
depends on SOC_IMX7D || SOC_IMX8MQ || (COMPILE_TEST && OF)
|
||||
depends on PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
default y if SOC_IMX7D
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
|
||||
obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o
|
||||
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#define GPU_VPU_PUP_REQ BIT(1)
|
||||
#define GPU_VPU_PDN_REQ BIT(0)
|
||||
|
||||
#define GPC_CLK_MAX 6
|
||||
#define GPC_CLK_MAX 7
|
||||
|
||||
#define PGC_DOMAIN_FLAG_NO_PD BIT(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,23 +14,54 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <dt-bindings/power/imx7-power.h>
|
||||
#include <dt-bindings/power/imx8mq-power.h>
|
||||
|
||||
#define GPC_LPCR_A_CORE_BSC 0x000
|
||||
|
||||
#define GPC_PGC_CPU_MAPPING 0x0ec
|
||||
#define USB_HSIC_PHY_A_CORE_DOMAIN BIT(6)
|
||||
#define USB_OTG2_PHY_A_CORE_DOMAIN BIT(5)
|
||||
#define USB_OTG1_PHY_A_CORE_DOMAIN BIT(4)
|
||||
#define PCIE_PHY_A_CORE_DOMAIN BIT(3)
|
||||
#define MIPI_PHY_A_CORE_DOMAIN BIT(2)
|
||||
|
||||
#define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6)
|
||||
#define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5)
|
||||
#define IMX7_USB_OTG1_PHY_A_CORE_DOMAIN BIT(4)
|
||||
#define IMX7_PCIE_PHY_A_CORE_DOMAIN BIT(3)
|
||||
#define IMX7_MIPI_PHY_A_CORE_DOMAIN BIT(2)
|
||||
|
||||
#define IMX8M_PCIE2_A53_DOMAIN BIT(15)
|
||||
#define IMX8M_MIPI_CSI2_A53_DOMAIN BIT(14)
|
||||
#define IMX8M_MIPI_CSI1_A53_DOMAIN BIT(13)
|
||||
#define IMX8M_DISP_A53_DOMAIN BIT(12)
|
||||
#define IMX8M_HDMI_A53_DOMAIN BIT(11)
|
||||
#define IMX8M_VPU_A53_DOMAIN BIT(10)
|
||||
#define IMX8M_GPU_A53_DOMAIN BIT(9)
|
||||
#define IMX8M_DDR2_A53_DOMAIN BIT(8)
|
||||
#define IMX8M_DDR1_A53_DOMAIN BIT(7)
|
||||
#define IMX8M_OTG2_A53_DOMAIN BIT(5)
|
||||
#define IMX8M_OTG1_A53_DOMAIN BIT(4)
|
||||
#define IMX8M_PCIE1_A53_DOMAIN BIT(3)
|
||||
#define IMX8M_MIPI_A53_DOMAIN BIT(2)
|
||||
|
||||
#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
|
||||
#define GPC_PU_PGC_SW_PDN_REQ 0x104
|
||||
#define USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
|
||||
#define USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
|
||||
#define USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
|
||||
#define PCIE_PHY_SW_Pxx_REQ BIT(1)
|
||||
#define MIPI_PHY_SW_Pxx_REQ BIT(0)
|
||||
|
||||
#define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4)
|
||||
#define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3)
|
||||
#define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2)
|
||||
#define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1)
|
||||
#define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0)
|
||||
|
||||
#define IMX8M_PCIE2_SW_Pxx_REQ BIT(13)
|
||||
#define IMX8M_MIPI_CSI2_SW_Pxx_REQ BIT(12)
|
||||
#define IMX8M_MIPI_CSI1_SW_Pxx_REQ BIT(11)
|
||||
#define IMX8M_DISP_SW_Pxx_REQ BIT(10)
|
||||
#define IMX8M_HDMI_SW_Pxx_REQ BIT(9)
|
||||
#define IMX8M_VPU_SW_Pxx_REQ BIT(8)
|
||||
#define IMX8M_GPU_SW_Pxx_REQ BIT(7)
|
||||
#define IMX8M_DDR2_SW_Pxx_REQ BIT(6)
|
||||
#define IMX8M_DDR1_SW_Pxx_REQ BIT(5)
|
||||
#define IMX8M_OTG2_SW_Pxx_REQ BIT(3)
|
||||
#define IMX8M_OTG1_SW_Pxx_REQ BIT(2)
|
||||
#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1)
|
||||
#define IMX8M_MIPI_SW_Pxx_REQ BIT(0)
|
||||
|
||||
#define GPC_M4_PU_PDN_FLG 0x1bc
|
||||
|
||||
|
|
@ -40,9 +71,22 @@
|
|||
* GPC_PGC memory map are incorrect, below offset
|
||||
* values are from design RTL.
|
||||
*/
|
||||
#define PGC_MIPI 16
|
||||
#define PGC_PCIE 17
|
||||
#define PGC_USB_HSIC 20
|
||||
#define IMX7_PGC_MIPI 16
|
||||
#define IMX7_PGC_PCIE 17
|
||||
#define IMX7_PGC_USB_HSIC 20
|
||||
|
||||
#define IMX8M_PGC_MIPI 16
|
||||
#define IMX8M_PGC_PCIE1 17
|
||||
#define IMX8M_PGC_OTG1 18
|
||||
#define IMX8M_PGC_OTG2 19
|
||||
#define IMX8M_PGC_DDR1 21
|
||||
#define IMX8M_PGC_GPU 23
|
||||
#define IMX8M_PGC_VPU 24
|
||||
#define IMX8M_PGC_DISP 26
|
||||
#define IMX8M_PGC_MIPI_CSI1 27
|
||||
#define IMX8M_PGC_MIPI_CSI2 28
|
||||
#define IMX8M_PGC_PCIE2 29
|
||||
|
||||
#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
|
||||
#define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc)
|
||||
|
||||
|
|
@ -67,6 +111,7 @@ struct imx_pgc_domain {
|
|||
struct imx_pgc_domain_data {
|
||||
const struct imx_pgc_domain *domains;
|
||||
size_t domains_num;
|
||||
const struct regmap_access_table *reg_access_table;
|
||||
};
|
||||
|
||||
static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
|
||||
|
|
@ -166,11 +211,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
|
|||
.name = "mipi-phy",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = MIPI_PHY_SW_Pxx_REQ,
|
||||
.map = MIPI_PHY_A_CORE_DOMAIN,
|
||||
.pxx = IMX7_MIPI_PHY_SW_Pxx_REQ,
|
||||
.map = IMX7_MIPI_PHY_A_CORE_DOMAIN,
|
||||
},
|
||||
.voltage = 1000000,
|
||||
.pgc = PGC_MIPI,
|
||||
.pgc = IMX7_PGC_MIPI,
|
||||
},
|
||||
|
||||
[IMX7_POWER_DOMAIN_PCIE_PHY] = {
|
||||
|
|
@ -178,11 +223,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
|
|||
.name = "pcie-phy",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = PCIE_PHY_SW_Pxx_REQ,
|
||||
.map = PCIE_PHY_A_CORE_DOMAIN,
|
||||
.pxx = IMX7_PCIE_PHY_SW_Pxx_REQ,
|
||||
.map = IMX7_PCIE_PHY_A_CORE_DOMAIN,
|
||||
},
|
||||
.voltage = 1000000,
|
||||
.pgc = PGC_PCIE,
|
||||
.pgc = IMX7_PGC_PCIE,
|
||||
},
|
||||
|
||||
[IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
|
||||
|
|
@ -190,17 +235,195 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {
|
|||
.name = "usb-hsic-phy",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = USB_HSIC_PHY_SW_Pxx_REQ,
|
||||
.map = USB_HSIC_PHY_A_CORE_DOMAIN,
|
||||
.pxx = IMX7_USB_HSIC_PHY_SW_Pxx_REQ,
|
||||
.map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN,
|
||||
},
|
||||
.voltage = 1200000,
|
||||
.pgc = PGC_USB_HSIC,
|
||||
.pgc = IMX7_PGC_USB_HSIC,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range imx7_yes_ranges[] = {
|
||||
regmap_reg_range(GPC_LPCR_A_CORE_BSC,
|
||||
GPC_M4_PU_PDN_FLG),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI),
|
||||
GPC_PGC_SR(IMX7_PGC_MIPI)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE),
|
||||
GPC_PGC_SR(IMX7_PGC_PCIE)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC),
|
||||
GPC_PGC_SR(IMX7_PGC_USB_HSIC)),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table imx7_access_table = {
|
||||
.yes_ranges = imx7_yes_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(imx7_yes_ranges),
|
||||
};
|
||||
|
||||
static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
|
||||
.domains = imx7_pgc_domains,
|
||||
.domains_num = ARRAY_SIZE(imx7_pgc_domains),
|
||||
.reg_access_table = &imx7_access_table,
|
||||
};
|
||||
|
||||
static const struct imx_pgc_domain imx8m_pgc_domains[] = {
|
||||
[IMX8M_POWER_DOMAIN_MIPI] = {
|
||||
.genpd = {
|
||||
.name = "mipi",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_MIPI_SW_Pxx_REQ,
|
||||
.map = IMX8M_MIPI_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_MIPI,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_PCIE1] = {
|
||||
.genpd = {
|
||||
.name = "pcie1",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_PCIE1_SW_Pxx_REQ,
|
||||
.map = IMX8M_PCIE1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_PCIE1,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_USB_OTG1] = {
|
||||
.genpd = {
|
||||
.name = "usb-otg1",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_OTG1_SW_Pxx_REQ,
|
||||
.map = IMX8M_OTG1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_OTG1,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_USB_OTG2] = {
|
||||
.genpd = {
|
||||
.name = "usb-otg2",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_OTG2_SW_Pxx_REQ,
|
||||
.map = IMX8M_OTG2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_OTG2,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_DDR1] = {
|
||||
.genpd = {
|
||||
.name = "ddr1",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_DDR1_SW_Pxx_REQ,
|
||||
.map = IMX8M_DDR2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_DDR1,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_GPU] = {
|
||||
.genpd = {
|
||||
.name = "gpu",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_GPU_SW_Pxx_REQ,
|
||||
.map = IMX8M_GPU_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_GPU,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_VPU] = {
|
||||
.genpd = {
|
||||
.name = "vpu",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_VPU_SW_Pxx_REQ,
|
||||
.map = IMX8M_VPU_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_VPU,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_DISP] = {
|
||||
.genpd = {
|
||||
.name = "disp",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_DISP_SW_Pxx_REQ,
|
||||
.map = IMX8M_DISP_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_DISP,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_MIPI_CSI1] = {
|
||||
.genpd = {
|
||||
.name = "mipi-csi1",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,
|
||||
.map = IMX8M_MIPI_CSI1_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_MIPI_CSI1,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_MIPI_CSI2] = {
|
||||
.genpd = {
|
||||
.name = "mipi-csi2",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,
|
||||
.map = IMX8M_MIPI_CSI2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_MIPI_CSI2,
|
||||
},
|
||||
|
||||
[IMX8M_POWER_DOMAIN_PCIE2] = {
|
||||
.genpd = {
|
||||
.name = "pcie2",
|
||||
},
|
||||
.bits = {
|
||||
.pxx = IMX8M_PCIE2_SW_Pxx_REQ,
|
||||
.map = IMX8M_PCIE2_A53_DOMAIN,
|
||||
},
|
||||
.pgc = IMX8M_PGC_PCIE2,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range imx8m_yes_ranges[] = {
|
||||
regmap_reg_range(GPC_LPCR_A_CORE_BSC,
|
||||
GPC_M4_PU_PDN_FLG),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI),
|
||||
GPC_PGC_SR(IMX8M_PGC_MIPI)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE1),
|
||||
GPC_PGC_SR(IMX8M_PGC_PCIE1)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG1),
|
||||
GPC_PGC_SR(IMX8M_PGC_OTG1)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG2),
|
||||
GPC_PGC_SR(IMX8M_PGC_OTG2)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DDR1),
|
||||
GPC_PGC_SR(IMX8M_PGC_DDR1)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_GPU),
|
||||
GPC_PGC_SR(IMX8M_PGC_GPU)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_VPU),
|
||||
GPC_PGC_SR(IMX8M_PGC_VPU)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DISP),
|
||||
GPC_PGC_SR(IMX8M_PGC_DISP)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI1),
|
||||
GPC_PGC_SR(IMX8M_PGC_MIPI_CSI1)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI2),
|
||||
GPC_PGC_SR(IMX8M_PGC_MIPI_CSI2)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE2),
|
||||
GPC_PGC_SR(IMX8M_PGC_PCIE2)),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table imx8m_access_table = {
|
||||
.yes_ranges = imx8m_yes_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(imx8m_yes_ranges),
|
||||
};
|
||||
|
||||
static const struct imx_pgc_domain_data imx8m_pgc_domain_data = {
|
||||
.domains = imx8m_pgc_domains,
|
||||
.domains_num = ARRAY_SIZE(imx8m_pgc_domains),
|
||||
.reg_access_table = &imx8m_access_table,
|
||||
};
|
||||
|
||||
static int imx_pgc_domain_probe(struct platform_device *pdev)
|
||||
|
|
@ -217,7 +440,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)
|
|||
dev_err(domain->dev, "Failed to get domain's regulator\n");
|
||||
return PTR_ERR(domain->regulator);
|
||||
}
|
||||
} else {
|
||||
} else if (domain->voltage) {
|
||||
regulator_set_voltage(domain->regulator,
|
||||
domain->voltage, domain->voltage);
|
||||
}
|
||||
|
|
@ -265,27 +488,15 @@ builtin_platform_driver(imx_pgc_domain_driver)
|
|||
|
||||
static int imx_gpcv2_probe(struct platform_device *pdev)
|
||||
{
|
||||
static const struct imx_pgc_domain_data *domain_data;
|
||||
static const struct regmap_range yes_ranges[] = {
|
||||
regmap_reg_range(GPC_LPCR_A_CORE_BSC,
|
||||
GPC_M4_PU_PDN_FLG),
|
||||
regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI),
|
||||
GPC_PGC_SR(PGC_MIPI)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(PGC_PCIE),
|
||||
GPC_PGC_SR(PGC_PCIE)),
|
||||
regmap_reg_range(GPC_PGC_CTRL(PGC_USB_HSIC),
|
||||
GPC_PGC_SR(PGC_USB_HSIC)),
|
||||
};
|
||||
static const struct regmap_access_table access_table = {
|
||||
.yes_ranges = yes_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(yes_ranges),
|
||||
};
|
||||
static const struct regmap_config regmap_config = {
|
||||
const struct imx_pgc_domain_data *domain_data =
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
|
||||
struct regmap_config regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.rd_table = &access_table,
|
||||
.wr_table = &access_table,
|
||||
.rd_table = domain_data->reg_access_table,
|
||||
.wr_table = domain_data->reg_access_table,
|
||||
.max_register = SZ_4K,
|
||||
};
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -313,8 +524,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
domain_data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
for_each_child_of_node(pgc_np, np) {
|
||||
struct platform_device *pd_pdev;
|
||||
struct imx_pgc_domain *domain;
|
||||
|
|
@ -372,6 +581,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
|||
|
||||
static const struct of_device_id imx_gpcv2_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, },
|
||||
{ .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,18 @@
|
|||
menu "MediaTek SoC drivers"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
|
||||
config MTK_CMDQ
|
||||
tristate "MediaTek CMDQ Support"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
select MAILBOX
|
||||
select MTK_CMDQ_MBOX
|
||||
select MTK_INFRACFG
|
||||
help
|
||||
Say yes here to add support for the MediaTek Command Queue (CMDQ)
|
||||
driver. The CMDQ is used to help read/write registers with critical
|
||||
time limitation, such as updating display configuration during the
|
||||
vblank.
|
||||
|
||||
config MTK_INFRACFG
|
||||
bool "MediaTek INFRACFG Support"
|
||||
select REGMAP
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
|
||||
obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
|
||||
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
|
||||
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
|
||||
|
|
|
|||
300
drivers/soc/mediatek/mtk-cmdq-helper.c
Normal file
300
drivers/soc/mediatek/mtk-cmdq-helper.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (c) 2018 MediaTek Inc.
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/soc/mediatek/mtk-cmdq.h>
|
||||
|
||||
#define CMDQ_ARG_A_WRITE_MASK 0xffff
|
||||
#define CMDQ_WRITE_ENABLE_MASK BIT(0)
|
||||
#define CMDQ_EOC_IRQ_EN BIT(0)
|
||||
#define CMDQ_EOC_CMD ((u64)((CMDQ_CODE_EOC << CMDQ_OP_CODE_SHIFT)) \
|
||||
<< 32 | CMDQ_EOC_IRQ_EN)
|
||||
|
||||
static void cmdq_client_timeout(struct timer_list *t)
|
||||
{
|
||||
struct cmdq_client *client = from_timer(client, t, timer);
|
||||
|
||||
dev_err(client->client.dev, "cmdq timeout!\n");
|
||||
}
|
||||
|
||||
struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout)
|
||||
{
|
||||
struct cmdq_client *client;
|
||||
|
||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return (struct cmdq_client *)-ENOMEM;
|
||||
|
||||
client->timeout_ms = timeout;
|
||||
if (timeout != CMDQ_NO_TIMEOUT) {
|
||||
spin_lock_init(&client->lock);
|
||||
timer_setup(&client->timer, cmdq_client_timeout, 0);
|
||||
}
|
||||
client->pkt_cnt = 0;
|
||||
client->client.dev = dev;
|
||||
client->client.tx_block = false;
|
||||
client->chan = mbox_request_channel(&client->client, index);
|
||||
|
||||
if (IS_ERR(client->chan)) {
|
||||
long err;
|
||||
|
||||
dev_err(dev, "failed to request channel\n");
|
||||
err = PTR_ERR(client->chan);
|
||||
kfree(client);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_mbox_create);
|
||||
|
||||
void cmdq_mbox_destroy(struct cmdq_client *client)
|
||||
{
|
||||
if (client->timeout_ms != CMDQ_NO_TIMEOUT) {
|
||||
spin_lock(&client->lock);
|
||||
del_timer_sync(&client->timer);
|
||||
spin_unlock(&client->lock);
|
||||
}
|
||||
mbox_free_channel(client->chan);
|
||||
kfree(client);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_mbox_destroy);
|
||||
|
||||
struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size)
|
||||
{
|
||||
struct cmdq_pkt *pkt;
|
||||
struct device *dev;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
|
||||
if (!pkt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
pkt->va_base = kzalloc(size, GFP_KERNEL);
|
||||
if (!pkt->va_base) {
|
||||
kfree(pkt);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
pkt->buf_size = size;
|
||||
pkt->cl = (void *)client;
|
||||
|
||||
dev = client->chan->mbox->dev;
|
||||
dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dev, dma_addr)) {
|
||||
dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
|
||||
kfree(pkt->va_base);
|
||||
kfree(pkt);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
pkt->pa_base = dma_addr;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_create);
|
||||
|
||||
void cmdq_pkt_destroy(struct cmdq_pkt *pkt)
|
||||
{
|
||||
struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
|
||||
|
||||
dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
|
||||
DMA_TO_DEVICE);
|
||||
kfree(pkt->va_base);
|
||||
kfree(pkt);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_destroy);
|
||||
|
||||
static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code,
|
||||
u32 arg_a, u32 arg_b)
|
||||
{
|
||||
u64 *cmd_ptr;
|
||||
|
||||
if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) {
|
||||
/*
|
||||
* In the case of allocated buffer size (pkt->buf_size) is used
|
||||
* up, the real required size (pkt->cmdq_buf_size) is still
|
||||
* increased, so that the user knows how much memory should be
|
||||
* ultimately allocated after appending all commands and
|
||||
* flushing the command packet. Therefor, the user can call
|
||||
* cmdq_pkt_create() again with the real required buffer size.
|
||||
*/
|
||||
pkt->cmd_buf_size += CMDQ_INST_SIZE;
|
||||
WARN_ONCE(1, "%s: buffer size %u is too small !\n",
|
||||
__func__, (u32)pkt->buf_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cmd_ptr = pkt->va_base + pkt->cmd_buf_size;
|
||||
(*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b;
|
||||
pkt->cmd_buf_size += CMDQ_INST_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset)
|
||||
{
|
||||
u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) |
|
||||
(subsys << CMDQ_SUBSYS_SHIFT);
|
||||
|
||||
return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write);
|
||||
|
||||
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
|
||||
u32 subsys, u32 offset, u32 mask)
|
||||
{
|
||||
u32 offset_mask = offset;
|
||||
int err = 0;
|
||||
|
||||
if (mask != 0xffffffff) {
|
||||
err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask);
|
||||
offset_mask |= CMDQ_WRITE_ENABLE_MASK;
|
||||
}
|
||||
err |= cmdq_pkt_write(pkt, value, subsys, offset_mask);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_write_mask);
|
||||
|
||||
int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event)
|
||||
{
|
||||
u32 arg_b;
|
||||
|
||||
if (event >= CMDQ_MAX_EVENT)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* WFE arg_b
|
||||
* bit 0-11: wait value
|
||||
* bit 15: 1 - wait, 0 - no wait
|
||||
* bit 16-27: update value
|
||||
* bit 31: 1 - update, 0 - no update
|
||||
*/
|
||||
arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, arg_b);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_wfe);
|
||||
|
||||
int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event)
|
||||
{
|
||||
if (event >= CMDQ_MAX_EVENT)
|
||||
return -EINVAL;
|
||||
|
||||
return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event,
|
||||
CMDQ_WFE_UPDATE);
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_clear_event);
|
||||
|
||||
static int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* insert EOC and generate IRQ for each command iteration */
|
||||
err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN);
|
||||
|
||||
/* JUMP to end */
|
||||
err |= cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void cmdq_pkt_flush_async_cb(struct cmdq_cb_data data)
|
||||
{
|
||||
struct cmdq_pkt *pkt = (struct cmdq_pkt *)data.data;
|
||||
struct cmdq_task_cb *cb = &pkt->cb;
|
||||
struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
|
||||
|
||||
if (client->timeout_ms != CMDQ_NO_TIMEOUT) {
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(&client->lock, flags);
|
||||
if (--client->pkt_cnt == 0)
|
||||
del_timer(&client->timer);
|
||||
else
|
||||
mod_timer(&client->timer, jiffies +
|
||||
msecs_to_jiffies(client->timeout_ms));
|
||||
spin_unlock_irqrestore(&client->lock, flags);
|
||||
}
|
||||
|
||||
dma_sync_single_for_cpu(client->chan->mbox->dev, pkt->pa_base,
|
||||
pkt->cmd_buf_size, DMA_TO_DEVICE);
|
||||
if (cb->cb) {
|
||||
data.data = cb->data;
|
||||
cb->cb(data);
|
||||
}
|
||||
}
|
||||
|
||||
int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb,
|
||||
void *data)
|
||||
{
|
||||
int err;
|
||||
unsigned long flags = 0;
|
||||
struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
|
||||
|
||||
err = cmdq_pkt_finalize(pkt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pkt->cb.cb = cb;
|
||||
pkt->cb.data = data;
|
||||
pkt->async_cb.cb = cmdq_pkt_flush_async_cb;
|
||||
pkt->async_cb.data = pkt;
|
||||
|
||||
dma_sync_single_for_device(client->chan->mbox->dev, pkt->pa_base,
|
||||
pkt->cmd_buf_size, DMA_TO_DEVICE);
|
||||
|
||||
if (client->timeout_ms != CMDQ_NO_TIMEOUT) {
|
||||
spin_lock_irqsave(&client->lock, flags);
|
||||
if (client->pkt_cnt++ == 0)
|
||||
mod_timer(&client->timer, jiffies +
|
||||
msecs_to_jiffies(client->timeout_ms));
|
||||
spin_unlock_irqrestore(&client->lock, flags);
|
||||
}
|
||||
|
||||
mbox_send_message(client->chan, pkt);
|
||||
/* We can send next packet immediately, so just call txdone. */
|
||||
mbox_client_txdone(client->chan, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_flush_async);
|
||||
|
||||
struct cmdq_flush_completion {
|
||||
struct completion cmplt;
|
||||
bool err;
|
||||
};
|
||||
|
||||
static void cmdq_pkt_flush_cb(struct cmdq_cb_data data)
|
||||
{
|
||||
struct cmdq_flush_completion *cmplt;
|
||||
|
||||
cmplt = (struct cmdq_flush_completion *)data.data;
|
||||
if (data.sta != CMDQ_CB_NORMAL)
|
||||
cmplt->err = true;
|
||||
else
|
||||
cmplt->err = false;
|
||||
complete(&cmplt->cmplt);
|
||||
}
|
||||
|
||||
int cmdq_pkt_flush(struct cmdq_pkt *pkt)
|
||||
{
|
||||
struct cmdq_flush_completion cmplt;
|
||||
int err;
|
||||
|
||||
init_completion(&cmplt.cmplt);
|
||||
err = cmdq_pkt_flush_async(pkt, cmdq_pkt_flush_cb, &cmplt);
|
||||
if (err < 0)
|
||||
return err;
|
||||
wait_for_completion(&cmplt.cmplt);
|
||||
|
||||
return cmplt.err ? -EFAULT : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cmdq_pkt_flush);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -75,11 +75,6 @@ config QCOM_QMI_HELPERS
|
|||
tristate
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
depends on NET
|
||||
help
|
||||
Helper library for handling QMI encoded messages. QMI encoded
|
||||
messages are used in communication between the majority of QRTR
|
||||
clients and this helpers provide the common functionality needed for
|
||||
doing this from a kernel driver.
|
||||
|
||||
config QCOM_RMTFS_MEM
|
||||
tristate "Qualcomm Remote Filesystem memory driver"
|
||||
|
|
|
|||
|
|
@ -101,8 +101,7 @@ static bool cmd_db_magic_matches(const struct cmd_db_header *header)
|
|||
|
||||
static struct cmd_db_header *cmd_db_header;
|
||||
|
||||
|
||||
static inline void *rsc_to_entry_header(struct rsc_hdr *hdr)
|
||||
static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr)
|
||||
{
|
||||
u16 offset = le16_to_cpu(hdr->header_offset);
|
||||
|
||||
|
|
@ -110,7 +109,7 @@ static inline void *rsc_to_entry_header(struct rsc_hdr *hdr)
|
|||
}
|
||||
|
||||
static inline void *
|
||||
rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent)
|
||||
rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent)
|
||||
{
|
||||
u16 offset = le16_to_cpu(hdr->data_offset);
|
||||
u16 loffset = le16_to_cpu(ent->offset);
|
||||
|
|
@ -134,11 +133,11 @@ int cmd_db_ready(void)
|
|||
}
|
||||
EXPORT_SYMBOL(cmd_db_ready);
|
||||
|
||||
static int cmd_db_get_header(const char *id, struct entry_header *eh,
|
||||
struct rsc_hdr *rh)
|
||||
static int cmd_db_get_header(const char *id, const struct entry_header **eh,
|
||||
const struct rsc_hdr **rh)
|
||||
{
|
||||
struct rsc_hdr *rsc_hdr;
|
||||
struct entry_header *ent;
|
||||
const struct rsc_hdr *rsc_hdr;
|
||||
const struct entry_header *ent;
|
||||
int ret, i, j;
|
||||
u8 query[8];
|
||||
|
||||
|
|
@ -146,9 +145,6 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!eh || !rh)
|
||||
return -EINVAL;
|
||||
|
||||
/* Pad out query string to same length as in DB */
|
||||
strncpy(query, id, sizeof(query));
|
||||
|
||||
|
|
@ -159,14 +155,13 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh,
|
|||
|
||||
ent = rsc_to_entry_header(rsc_hdr);
|
||||
for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) {
|
||||
if (memcmp(ent->id, query, sizeof(ent->id)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < le16_to_cpu(rsc_hdr->cnt)) {
|
||||
memcpy(eh, ent, sizeof(*ent));
|
||||
memcpy(rh, rsc_hdr, sizeof(*rh));
|
||||
return 0;
|
||||
if (memcmp(ent->id, query, sizeof(ent->id)) == 0) {
|
||||
if (eh)
|
||||
*eh = ent;
|
||||
if (rh)
|
||||
*rh = rsc_hdr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,68 +181,39 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh,
|
|||
u32 cmd_db_read_addr(const char *id)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
const struct entry_header *ent;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
ret = cmd_db_get_header(id, &ent, NULL);
|
||||
|
||||
return ret < 0 ? 0 : le32_to_cpu(ent.addr);
|
||||
return ret < 0 ? 0 : le32_to_cpu(ent->addr);
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_addr);
|
||||
|
||||
/**
|
||||
* cmd_db_read_aux_data() - Query command db for aux data.
|
||||
*
|
||||
* @id: Resource to retrieve AUX Data on.
|
||||
* @data: Data buffer to copy returned aux data to. Returns size on NULL
|
||||
* @len: Caller provides size of data buffer passed in.
|
||||
* @id: Resource to retrieve AUX Data on
|
||||
* @len: size of data buffer returned
|
||||
*
|
||||
* Return: size of data on success, errno otherwise
|
||||
* Return: pointer to data on success, error pointer otherwise
|
||||
*/
|
||||
int cmd_db_read_aux_data(const char *id, u8 *data, size_t len)
|
||||
const void *cmd_db_read_aux_data(const char *id, size_t *len)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
u16 ent_len;
|
||||
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
const struct entry_header *ent;
|
||||
const struct rsc_hdr *rsc_hdr;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ent_len = le16_to_cpu(ent.len);
|
||||
if (len < ent_len)
|
||||
return -EINVAL;
|
||||
if (len)
|
||||
*len = le16_to_cpu(ent->len);
|
||||
|
||||
len = min_t(u16, ent_len, len);
|
||||
memcpy(data, rsc_offset(&rsc_hdr, &ent), len);
|
||||
|
||||
return len;
|
||||
return rsc_offset(rsc_hdr, ent);
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_aux_data);
|
||||
|
||||
/**
|
||||
* cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB.
|
||||
*
|
||||
* @id: Resource to retrieve AUX Data.
|
||||
*
|
||||
* Return: size on success, 0 on error
|
||||
*/
|
||||
size_t cmd_db_read_aux_data_len(const char *id)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
|
||||
return ret < 0 ? 0 : le16_to_cpu(ent.len);
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_aux_data_len);
|
||||
|
||||
/**
|
||||
* cmd_db_read_slave_id - Get the slave ID for a given resource address
|
||||
*
|
||||
|
|
@ -258,15 +224,14 @@ EXPORT_SYMBOL(cmd_db_read_aux_data_len);
|
|||
enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
const struct entry_header *ent;
|
||||
u32 addr;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
ret = cmd_db_get_header(id, &ent, NULL);
|
||||
if (ret < 0)
|
||||
return CMD_DB_HW_INVALID;
|
||||
|
||||
addr = le32_to_cpu(ent.addr);
|
||||
addr = le32_to_cpu(ent->addr);
|
||||
return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_slave_id);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ EXPORT_SYMBOL_GPL(llcc_slice_getd);
|
|||
*/
|
||||
void llcc_slice_putd(struct llcc_slice_desc *desc)
|
||||
{
|
||||
kfree(desc);
|
||||
if (!IS_ERR_OR_NULL(desc))
|
||||
kfree(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(llcc_slice_putd);
|
||||
|
||||
|
|
@ -142,6 +143,9 @@ int llcc_slice_activate(struct llcc_slice_desc *desc)
|
|||
int ret;
|
||||
u32 act_ctrl_val;
|
||||
|
||||
if (IS_ERR_OR_NULL(desc))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
if (test_bit(desc->slice_id, drv_data->bitmap)) {
|
||||
mutex_unlock(&drv_data->lock);
|
||||
|
|
@ -176,6 +180,9 @@ int llcc_slice_deactivate(struct llcc_slice_desc *desc)
|
|||
u32 act_ctrl_val;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(desc))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&drv_data->lock);
|
||||
if (!test_bit(desc->slice_id, drv_data->bitmap)) {
|
||||
mutex_unlock(&drv_data->lock);
|
||||
|
|
@ -203,6 +210,9 @@ EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
|
|||
*/
|
||||
int llcc_get_slice_id(struct llcc_slice_desc *desc)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(desc))
|
||||
return -EINVAL;
|
||||
|
||||
return desc->slice_id;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(llcc_get_slice_id);
|
||||
|
|
@ -213,6 +223,9 @@ EXPORT_SYMBOL_GPL(llcc_get_slice_id);
|
|||
*/
|
||||
size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(desc))
|
||||
return 0;
|
||||
|
||||
return desc->slice_size;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(llcc_get_slice_size);
|
||||
|
|
@ -360,5 +373,5 @@ int qcom_llcc_probe(struct platform_device *pdev,
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_llcc_probe);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller");
|
||||
|
|
|
|||
|
|
@ -215,6 +215,16 @@ static void geni_se_io_init(void __iomem *base)
|
|||
writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG);
|
||||
}
|
||||
|
||||
static void geni_se_irq_clear(struct geni_se *se)
|
||||
{
|
||||
writel_relaxed(0, se->base + SE_GSI_EVENT_EN);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_IRQ_EN);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_init() - Initialize the GENI serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
|
|
@ -228,6 +238,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr)
|
|||
{
|
||||
u32 val;
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
geni_se_io_init(se->base);
|
||||
geni_se_io_set_mode(se->base);
|
||||
|
||||
|
|
@ -249,12 +260,7 @@ static void geni_se_select_fifo_mode(struct geni_se *se)
|
|||
u32 proto = geni_se_read_proto(se);
|
||||
u32 val;
|
||||
|
||||
writel_relaxed(0, se->base + SE_GSI_EVENT_EN);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_IRQ_EN);
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
if (proto != GENI_SE_UART) {
|
||||
|
|
@ -277,12 +283,7 @@ static void geni_se_select_dma_mode(struct geni_se *se)
|
|||
{
|
||||
u32 val;
|
||||
|
||||
writel_relaxed(0, se->base + SE_GSI_EVENT_EN);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_IRQ_EN);
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val |= GENI_DMA_MODE_EN;
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn,
|
|||
txn->dest = c_struct;
|
||||
|
||||
mutex_lock(&qmi->txn_lock);
|
||||
ret = idr_alloc_cyclic(&qmi->txns, txn, 0, INT_MAX, GFP_KERNEL);
|
||||
ret = idr_alloc_cyclic(&qmi->txns, txn, 0, U16_MAX, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
pr_err("failed to allocate transaction id\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
|
|||
{ .compatible = "qcom,rpm-msm8974" },
|
||||
{ .compatible = "qcom,rpm-msm8996" },
|
||||
{ .compatible = "qcom,rpm-msm8998" },
|
||||
{ .compatible = "qcom,rpm-qcs404" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ static const struct rcar_sysc_area r8a77965_areas[] __initconst = {
|
|||
{ "a2vc1", 0x3c0, 1, R8A77965_PD_A2VC1, R8A77965_PD_A3VC },
|
||||
{ "3dg-a", 0x100, 0, R8A77965_PD_3DG_A, R8A77965_PD_ALWAYS_ON },
|
||||
{ "3dg-b", 0x100, 1, R8A77965_PD_3DG_B, R8A77965_PD_3DG_A },
|
||||
{ "a3ir", 0x180, 0, R8A77965_PD_A3IR, R8A77965_PD_ALWAYS_ON },
|
||||
};
|
||||
|
||||
const struct rcar_sysc_info r8a77965_sysc_info __initconst = {
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = {
|
|||
PD_CPU_NOCR },
|
||||
{ "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU,
|
||||
PD_CPU_NOCR },
|
||||
{ "cr7", 0x240, 0, R8A77970_PD_CR7, R8A77970_PD_ALWAYS_ON },
|
||||
{ "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON },
|
||||
{ "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR },
|
||||
{ "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR },
|
||||
{ "a2ir2", 0x400, 2, R8A77970_PD_A2IR2, R8A77970_PD_A3IR },
|
||||
{ "a2ir3", 0x400, 3, R8A77970_PD_A2IR3, R8A77970_PD_A3IR },
|
||||
{ "a2dp", 0x400, 2, R8A77970_PD_A2DP, R8A77970_PD_A3IR },
|
||||
{ "a2cn", 0x400, 3, R8A77970_PD_A2CN, R8A77970_PD_A3IR },
|
||||
{ "a2sc0", 0x400, 4, R8A77970_PD_A2SC0, R8A77970_PD_A3IR },
|
||||
{ "a2sc1", 0x400, 5, R8A77970_PD_A2SC1, R8A77970_PD_A3IR },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = {
|
|||
{ "a2sc2", 0x400, 8, R8A77980_PD_A2SC2, R8A77980_PD_A3IR },
|
||||
{ "a2sc3", 0x400, 9, R8A77980_PD_A2SC3, R8A77980_PD_A3IR },
|
||||
{ "a2sc4", 0x400, 10, R8A77980_PD_A2SC4, R8A77980_PD_A3IR },
|
||||
{ "a2pd0", 0x400, 11, R8A77980_PD_A2PD0, R8A77980_PD_A3IR },
|
||||
{ "a2pd1", 0x400, 12, R8A77980_PD_A2PD1, R8A77980_PD_A3IR },
|
||||
{ "a2dp0", 0x400, 11, R8A77980_PD_A2DP0, R8A77980_PD_A3IR },
|
||||
{ "a2dp1", 0x400, 12, R8A77980_PD_A2DP1, R8A77980_PD_A3IR },
|
||||
{ "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR },
|
||||
{ "a3vip", 0x2c0, 0, R8A77980_PD_A3VIP, R8A77980_PD_ALWAYS_ON },
|
||||
{ "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_A3VIP },
|
||||
{ "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_A3VIP },
|
||||
{ "a3vip0", 0x2c0, 0, R8A77980_PD_A3VIP0, R8A77980_PD_ALWAYS_ON },
|
||||
{ "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_ALWAYS_ON },
|
||||
{ "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_ALWAYS_ON },
|
||||
};
|
||||
|
||||
const struct rcar_sysc_info r8a77980_sysc_info __initconst = {
|
||||
|
|
|
|||
|
|
@ -28,19 +28,6 @@ static struct rcar_sysc_area r8a77990_areas[] __initdata = {
|
|||
{ "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A },
|
||||
};
|
||||
|
||||
static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas,
|
||||
unsigned int num_areas, u8 id,
|
||||
int new_parent)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_areas; i++)
|
||||
if (areas[i].isr_bit == id) {
|
||||
areas[i].parent = new_parent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fixups for R-Car E3 ES1.0 revision */
|
||||
static const struct soc_device_attribute r8a77990[] __initconst = {
|
||||
{ .soc_id = "r8a77990", .revision = "ES1.0" },
|
||||
|
|
@ -50,12 +37,10 @@ static const struct soc_device_attribute r8a77990[] __initconst = {
|
|||
static int __init r8a77990_sysc_init(void)
|
||||
{
|
||||
if (soc_device_match(r8a77990)) {
|
||||
rcar_sysc_fix_parent(r8a77990_areas,
|
||||
ARRAY_SIZE(r8a77990_areas),
|
||||
R8A77990_PD_3DG_A, R8A77990_PD_3DG_B);
|
||||
rcar_sysc_fix_parent(r8a77990_areas,
|
||||
ARRAY_SIZE(r8a77990_areas),
|
||||
R8A77990_PD_3DG_B, R8A77990_PD_ALWAYS_ON);
|
||||
/* Fix incorrect 3DG hierarchy */
|
||||
swap(r8a77990_areas[7], r8a77990_areas[8]);
|
||||
r8a77990_areas[7].parent = R8A77990_PD_ALWAYS_ON;
|
||||
r8a77990_areas[8].parent = R8A77990_PD_3DG_B;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,15 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
|
|||
|
||||
spin_lock_irqsave(&rcar_sysc_lock, flags);
|
||||
|
||||
/*
|
||||
* The interrupt source needs to be enabled, but masked, to prevent the
|
||||
* CPU from receiving it.
|
||||
*/
|
||||
iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask,
|
||||
rcar_sysc_base + SYSCIMR);
|
||||
iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask,
|
||||
rcar_sysc_base + SYSCIER);
|
||||
|
||||
iowrite32(isr_mask, rcar_sysc_base + SYSCISCR);
|
||||
|
||||
/* Submit power shutoff or resume request until it was accepted */
|
||||
|
|
@ -146,16 +155,6 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch)
|
||||
{
|
||||
return rcar_sysc_power(sysc_ch, false);
|
||||
}
|
||||
|
||||
static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch)
|
||||
{
|
||||
return rcar_sysc_power(sysc_ch, true);
|
||||
}
|
||||
|
||||
static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch)
|
||||
{
|
||||
unsigned int st;
|
||||
|
|
@ -184,7 +183,7 @@ static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
|
|||
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, genpd->name);
|
||||
return rcar_sysc_power_down(&pd->ch);
|
||||
return rcar_sysc_power(&pd->ch, false);
|
||||
}
|
||||
|
||||
static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
|
||||
|
|
@ -192,7 +191,7 @@ static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
|
|||
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
|
||||
|
||||
pr_debug("%s: %s\n", __func__, genpd->name);
|
||||
return rcar_sysc_power_up(&pd->ch);
|
||||
return rcar_sysc_power(&pd->ch, true);
|
||||
}
|
||||
|
||||
static bool has_cpg_mstp;
|
||||
|
|
@ -252,7 +251,7 @@ static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
|
|||
goto finalize;
|
||||
}
|
||||
|
||||
rcar_sysc_power_up(&pd->ch);
|
||||
rcar_sysc_power(&pd->ch, true);
|
||||
|
||||
finalize:
|
||||
error = pm_genpd_init(genpd, gov, false);
|
||||
|
|
@ -334,7 +333,6 @@ static int __init rcar_sysc_pd_init(void)
|
|||
const struct of_device_id *match;
|
||||
struct rcar_pm_domains *domains;
|
||||
struct device_node *np;
|
||||
u32 syscier, syscimr;
|
||||
void __iomem *base;
|
||||
unsigned int i;
|
||||
int error;
|
||||
|
|
@ -373,27 +371,6 @@ static int __init rcar_sysc_pd_init(void)
|
|||
domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains);
|
||||
rcar_sysc_onecell_data = &domains->onecell_data;
|
||||
|
||||
for (i = 0, syscier = 0; i < info->num_areas; i++)
|
||||
syscier |= BIT(info->areas[i].isr_bit);
|
||||
|
||||
/*
|
||||
* Mask all interrupt sources to prevent the CPU from receiving them.
|
||||
* Make sure not to clear reserved bits that were set before.
|
||||
*/
|
||||
syscimr = ioread32(base + SYSCIMR);
|
||||
syscimr |= syscier;
|
||||
pr_debug("%pOF: syscimr = 0x%08x\n", np, syscimr);
|
||||
iowrite32(syscimr, base + SYSCIMR);
|
||||
|
||||
/*
|
||||
* SYSC needs all interrupt sources enabled to control power.
|
||||
*/
|
||||
pr_debug("%pOF: syscier = 0x%08x\n", np, syscier);
|
||||
iowrite32(syscier, base + SYSCIER);
|
||||
|
||||
/*
|
||||
* First, create all PM domains
|
||||
*/
|
||||
for (i = 0; i < info->num_areas; i++) {
|
||||
const struct rcar_sysc_area *area = &info->areas[i];
|
||||
struct rcar_sysc_pd *pd;
|
||||
|
|
@ -421,22 +398,17 @@ static int __init rcar_sysc_pd_init(void)
|
|||
goto out_put;
|
||||
|
||||
domains->domains[area->isr_bit] = &pd->genpd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Second, link all PM domains to their parents
|
||||
*/
|
||||
for (i = 0; i < info->num_areas; i++) {
|
||||
const struct rcar_sysc_area *area = &info->areas[i];
|
||||
|
||||
if (!area->name || area->parent < 0)
|
||||
if (area->parent < 0)
|
||||
continue;
|
||||
|
||||
error = pm_genpd_add_subdomain(domains->domains[area->parent],
|
||||
domains->domains[area->isr_bit]);
|
||||
if (error)
|
||||
&pd->genpd);
|
||||
if (error) {
|
||||
pr_warn("Failed to add PM subdomain %s to parent %u\n",
|
||||
area->name, area->parent);
|
||||
goto out_put;
|
||||
}
|
||||
}
|
||||
|
||||
error = of_genpd_add_provider_onecell(np, &domains->onecell_data);
|
||||
|
|
@ -478,8 +450,7 @@ static int rcar_sysc_power_cpu(unsigned int idx, bool on)
|
|||
if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx)
|
||||
continue;
|
||||
|
||||
return on ? rcar_sysc_power_up(&pd->ch)
|
||||
: rcar_sysc_power_down(&pd->ch);
|
||||
return rcar_sysc_power(&pd->ch, on);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@
|
|||
#include <linux/mfd/syscon.h>
|
||||
#include <dt-bindings/power/px30-power.h>
|
||||
#include <dt-bindings/power/rk3036-power.h>
|
||||
#include <dt-bindings/power/rk3066-power.h>
|
||||
#include <dt-bindings/power/rk3128-power.h>
|
||||
#include <dt-bindings/power/rk3188-power.h>
|
||||
#include <dt-bindings/power/rk3228-power.h>
|
||||
#include <dt-bindings/power/rk3288-power.h>
|
||||
#include <dt-bindings/power/rk3328-power.h>
|
||||
|
|
@ -737,6 +739,14 @@ static const struct rockchip_domain_info rk3036_pm_domains[] = {
|
|||
[RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3066_pm_domains[] = {
|
||||
[RK3066_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false),
|
||||
[RK3066_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false),
|
||||
[RK3066_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false),
|
||||
[RK3066_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false),
|
||||
[RK3066_PD_CPU] = DOMAIN(-1, 5, 1, 26, 31, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3128_pm_domains[] = {
|
||||
[RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false),
|
||||
[RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true),
|
||||
|
|
@ -745,6 +755,14 @@ static const struct rockchip_domain_info rk3128_pm_domains[] = {
|
|||
[RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3188_pm_domains[] = {
|
||||
[RK3188_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false),
|
||||
[RK3188_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false),
|
||||
[RK3188_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false),
|
||||
[RK3188_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false),
|
||||
[RK3188_PD_CPU] = DOMAIN(5, 5, 1, 26, 31, false),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3228_pm_domains[] = {
|
||||
[RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true),
|
||||
[RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true),
|
||||
|
|
@ -846,6 +864,17 @@ static const struct rockchip_pmu_info rk3036_pmu = {
|
|||
.domain_info = rk3036_pm_domains,
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3066_pmu = {
|
||||
.pwr_offset = 0x08,
|
||||
.status_offset = 0x0c,
|
||||
.req_offset = 0x38, /* PMU_MISC_CON1 */
|
||||
.idle_offset = 0x0c,
|
||||
.ack_offset = 0x0c,
|
||||
|
||||
.num_domains = ARRAY_SIZE(rk3066_pm_domains),
|
||||
.domain_info = rk3066_pm_domains,
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3128_pmu = {
|
||||
.pwr_offset = 0x04,
|
||||
.status_offset = 0x08,
|
||||
|
|
@ -857,6 +886,17 @@ static const struct rockchip_pmu_info rk3128_pmu = {
|
|||
.domain_info = rk3128_pm_domains,
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3188_pmu = {
|
||||
.pwr_offset = 0x08,
|
||||
.status_offset = 0x0c,
|
||||
.req_offset = 0x38, /* PMU_MISC_CON1 */
|
||||
.idle_offset = 0x0c,
|
||||
.ack_offset = 0x0c,
|
||||
|
||||
.num_domains = ARRAY_SIZE(rk3188_pm_domains),
|
||||
.domain_info = rk3188_pm_domains,
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3228_pmu = {
|
||||
.req_offset = 0x40c,
|
||||
.idle_offset = 0x488,
|
||||
|
|
@ -948,10 +988,18 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = {
|
|||
.compatible = "rockchip,rk3036-power-controller",
|
||||
.data = (void *)&rk3036_pmu,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3066-power-controller",
|
||||
.data = (void *)&rk3066_pmu,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3128-power-controller",
|
||||
.data = (void *)&rk3128_pmu,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3188-power-controller",
|
||||
.data = (void *)&rk3188_pmu,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3228-power-controller",
|
||||
.data = (void *)&rk3228_pmu,
|
||||
|
|
|
|||
|
|
@ -155,17 +155,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_sram_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, sunxi_sram_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations sunxi_sram_fops = {
|
||||
.open = sunxi_sram_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(sunxi_sram);
|
||||
|
||||
static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data)
|
||||
{
|
||||
|
|
@ -300,6 +290,10 @@ static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
|
|||
/* Nothing special */
|
||||
};
|
||||
|
||||
static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = {
|
||||
.has_emac_clock = true,
|
||||
};
|
||||
|
||||
static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
|
||||
.has_emac_clock = true,
|
||||
};
|
||||
|
|
@ -379,7 +373,7 @@ static const struct of_device_id sunxi_sram_dt_match[] = {
|
|||
},
|
||||
{
|
||||
.compatible = "allwinner,sun8i-h3-system-control",
|
||||
.data = &sun4i_a10_sramc_variant,
|
||||
.data = &sun8i_h3_sramc_variant,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun50i-a64-sram-controller",
|
||||
|
|
@ -389,6 +383,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = {
|
|||
.compatible = "allwinner,sun50i-a64-system-control",
|
||||
.data = &sun50i_a64_sramc_variant,
|
||||
},
|
||||
{
|
||||
.compatible = "allwinner,sun50i-h5-system-control",
|
||||
.data = &sun50i_a64_sramc_variant,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match);
|
||||
|
|
|
|||
|
|
@ -22,11 +22,15 @@ static const struct of_device_id tegra_machine_match[] = {
|
|||
|
||||
bool soc_is_tegra(void)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device_node *root;
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
if (!root)
|
||||
return false;
|
||||
|
||||
return of_match_node(tegra_machine_match, root) != NULL;
|
||||
match = of_match_node(tegra_machine_match, root);
|
||||
of_node_put(root);
|
||||
|
||||
return match != NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
* drivers/soc/tegra/pmc.c
|
||||
*
|
||||
* Copyright (c) 2010 Google, Inc
|
||||
* Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
|
|
@ -29,9 +30,12 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_clk.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
|
|
@ -48,7 +52,10 @@
|
|||
#include <soc/tegra/fuse.h>
|
||||
#include <soc/tegra/pmc.h>
|
||||
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
|
||||
#include <dt-bindings/gpio/tegra186-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra194-gpio.h>
|
||||
|
||||
#define PMC_CNTRL 0x0
|
||||
#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */
|
||||
|
|
@ -92,7 +99,6 @@
|
|||
#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2)
|
||||
#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1)
|
||||
|
||||
#define PMC_RST_STATUS 0x1b4
|
||||
#define PMC_RST_STATUS_POR 0
|
||||
#define PMC_RST_STATUS_WATCHDOG 1
|
||||
#define PMC_RST_STATUS_SENSOR 2
|
||||
|
|
@ -126,6 +132,16 @@
|
|||
#define GPU_RG_CNTRL 0x2d4
|
||||
|
||||
/* Tegra186 and later */
|
||||
#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2))
|
||||
#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3)
|
||||
#define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2))
|
||||
#define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2))
|
||||
#define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2))
|
||||
#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2))
|
||||
#define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2))
|
||||
#define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2))
|
||||
#define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2))
|
||||
|
||||
#define WAKE_AOWAKE_CTRL 0x4f4
|
||||
#define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
|
||||
|
||||
|
|
@ -151,8 +167,45 @@ struct tegra_pmc_regs {
|
|||
unsigned int dpd_status;
|
||||
unsigned int dpd2_req;
|
||||
unsigned int dpd2_status;
|
||||
unsigned int rst_status;
|
||||
unsigned int rst_source_shift;
|
||||
unsigned int rst_source_mask;
|
||||
unsigned int rst_level_shift;
|
||||
unsigned int rst_level_mask;
|
||||
};
|
||||
|
||||
struct tegra_wake_event {
|
||||
const char *name;
|
||||
unsigned int id;
|
||||
unsigned int irq;
|
||||
struct {
|
||||
unsigned int instance;
|
||||
unsigned int pin;
|
||||
} gpio;
|
||||
};
|
||||
|
||||
#define TEGRA_WAKE_IRQ(_name, _id, _irq) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.id = _id, \
|
||||
.irq = _irq, \
|
||||
.gpio = { \
|
||||
.instance = UINT_MAX, \
|
||||
.pin = UINT_MAX, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.id = _id, \
|
||||
.irq = 0, \
|
||||
.gpio = { \
|
||||
.instance = _instance, \
|
||||
.pin = _pin, \
|
||||
}, \
|
||||
}
|
||||
|
||||
struct tegra_pmc_soc {
|
||||
unsigned int num_powergates;
|
||||
const char *const *powergates;
|
||||
|
|
@ -175,6 +228,45 @@ struct tegra_pmc_soc {
|
|||
void (*setup_irq_polarity)(struct tegra_pmc *pmc,
|
||||
struct device_node *np,
|
||||
bool invert);
|
||||
|
||||
const char * const *reset_sources;
|
||||
unsigned int num_reset_sources;
|
||||
const char * const *reset_levels;
|
||||
unsigned int num_reset_levels;
|
||||
|
||||
const struct tegra_wake_event *wake_events;
|
||||
unsigned int num_wake_events;
|
||||
};
|
||||
|
||||
static const char * const tegra186_reset_sources[] = {
|
||||
"SYS_RESET",
|
||||
"AOWDT",
|
||||
"MCCPLEXWDT",
|
||||
"BPMPWDT",
|
||||
"SCEWDT",
|
||||
"SPEWDT",
|
||||
"APEWDT",
|
||||
"BCCPLEXWDT",
|
||||
"SENSOR",
|
||||
"AOTAG",
|
||||
"VFSENSOR",
|
||||
"SWREST",
|
||||
"SC7",
|
||||
"HSM",
|
||||
"CORESIGHT"
|
||||
};
|
||||
|
||||
static const char * const tegra186_reset_levels[] = {
|
||||
"L0", "L1", "L2", "WARM"
|
||||
};
|
||||
|
||||
static const char * const tegra30_reset_sources[] = {
|
||||
"POWER_ON_RESET",
|
||||
"WATCHDOG",
|
||||
"SENSOR",
|
||||
"SW_MAIN",
|
||||
"LP0",
|
||||
"AOTAG"
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -230,6 +322,9 @@ struct tegra_pmc {
|
|||
struct mutex powergates_lock;
|
||||
|
||||
struct pinctrl_dev *pctl_dev;
|
||||
|
||||
struct irq_domain *domain;
|
||||
struct irq_chip irq;
|
||||
};
|
||||
|
||||
static struct tegra_pmc *pmc = &(struct tegra_pmc) {
|
||||
|
|
@ -538,16 +633,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off);
|
|||
*/
|
||||
int tegra_powergate_is_powered(unsigned int id)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (!tegra_powergate_is_valid(id))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&pmc->powergates_lock);
|
||||
status = tegra_powergate_state(id);
|
||||
mutex_unlock(&pmc->powergates_lock);
|
||||
|
||||
return status;
|
||||
return tegra_powergate_state(id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -715,17 +804,7 @@ static int powergate_show(struct seq_file *s, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int powergate_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, powergate_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations powergate_fops = {
|
||||
.open = powergate_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(powergate);
|
||||
|
||||
static int tegra_powergate_debugfs_init(void)
|
||||
{
|
||||
|
|
@ -845,22 +924,6 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
|
|||
goto remove_resets;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: If XHCI is enabled for Tegra, then power-up the XUSB
|
||||
* host and super-speed partitions. Once the XHCI driver
|
||||
* manages the partitions itself this code can be removed. Note
|
||||
* that we don't register these partitions with the genpd core
|
||||
* to avoid it from powering down the partitions as they appear
|
||||
* to be unused.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) &&
|
||||
(id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) {
|
||||
if (off)
|
||||
WARN_ON(tegra_powergate_power_up(pg, true));
|
||||
|
||||
goto remove_resets;
|
||||
}
|
||||
|
||||
err = pm_genpd_init(&pg->genpd, NULL, off);
|
||||
if (err < 0) {
|
||||
pr_err("failed to initialise PM domain %pOFn: %d\n", np,
|
||||
|
|
@ -1541,6 +1604,225 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
|
|||
return err;
|
||||
}
|
||||
|
||||
static ssize_t reset_reason_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value, rst_src;
|
||||
|
||||
value = tegra_pmc_readl(pmc->soc->regs->rst_status);
|
||||
rst_src = (value & pmc->soc->regs->rst_source_mask) >>
|
||||
pmc->soc->regs->rst_source_shift;
|
||||
|
||||
return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(reset_reason);
|
||||
|
||||
static ssize_t reset_level_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u32 value, rst_lvl;
|
||||
|
||||
value = tegra_pmc_readl(pmc->soc->regs->rst_status);
|
||||
rst_lvl = (value & pmc->soc->regs->rst_level_mask) >>
|
||||
pmc->soc->regs->rst_level_shift;
|
||||
|
||||
return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(reset_level);
|
||||
|
||||
static void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc)
|
||||
{
|
||||
struct device *dev = pmc->dev;
|
||||
int err = 0;
|
||||
|
||||
if (pmc->soc->reset_sources) {
|
||||
err = device_create_file(dev, &dev_attr_reset_reason);
|
||||
if (err < 0)
|
||||
dev_warn(dev,
|
||||
"failed to create attr \"reset_reason\": %d\n",
|
||||
err);
|
||||
}
|
||||
|
||||
if (pmc->soc->reset_levels) {
|
||||
err = device_create_file(dev, &dev_attr_reset_level);
|
||||
if (err < 0)
|
||||
dev_warn(dev,
|
||||
"failed to create attr \"reset_level\": %d\n",
|
||||
err);
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra_pmc_irq_translate(struct irq_domain *domain,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned long *hwirq,
|
||||
unsigned int *type)
|
||||
{
|
||||
if (WARN_ON(fwspec->param_count < 2))
|
||||
return -EINVAL;
|
||||
|
||||
*hwirq = fwspec->param[0];
|
||||
*type = fwspec->param[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int num_irqs, void *data)
|
||||
{
|
||||
struct tegra_pmc *pmc = domain->host_data;
|
||||
const struct tegra_pmc_soc *soc = pmc->soc;
|
||||
struct irq_fwspec *fwspec = data;
|
||||
unsigned int i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; i < soc->num_wake_events; i++) {
|
||||
const struct tegra_wake_event *event = &soc->wake_events[i];
|
||||
|
||||
if (fwspec->param_count == 2) {
|
||||
struct irq_fwspec spec;
|
||||
|
||||
if (event->id != fwspec->param[0])
|
||||
continue;
|
||||
|
||||
err = irq_domain_set_hwirq_and_chip(domain, virq,
|
||||
event->id,
|
||||
&pmc->irq, pmc);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
spec.fwnode = &pmc->dev->of_node->fwnode;
|
||||
spec.param_count = 3;
|
||||
spec.param[0] = GIC_SPI;
|
||||
spec.param[1] = event->irq;
|
||||
spec.param[2] = fwspec->param[1];
|
||||
|
||||
err = irq_domain_alloc_irqs_parent(domain, virq,
|
||||
num_irqs, &spec);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (fwspec->param_count == 3) {
|
||||
if (event->gpio.instance != fwspec->param[0] ||
|
||||
event->gpio.pin != fwspec->param[1])
|
||||
continue;
|
||||
|
||||
err = irq_domain_set_hwirq_and_chip(domain, virq,
|
||||
event->id,
|
||||
&pmc->irq, pmc);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == soc->num_wake_events)
|
||||
err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX,
|
||||
&pmc->irq, pmc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops tegra_pmc_irq_domain_ops = {
|
||||
.translate = tegra_pmc_irq_translate,
|
||||
.alloc = tegra_pmc_irq_alloc,
|
||||
};
|
||||
|
||||
static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
|
||||
unsigned int offset, bit;
|
||||
u32 value;
|
||||
|
||||
offset = data->hwirq / 32;
|
||||
bit = data->hwirq % 32;
|
||||
|
||||
/* clear wake status */
|
||||
writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq));
|
||||
|
||||
/* route wake to tier 2 */
|
||||
value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset));
|
||||
|
||||
if (!on)
|
||||
value &= ~(1 << bit);
|
||||
else
|
||||
value |= 1 << bit;
|
||||
|
||||
writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset));
|
||||
|
||||
/* enable wakeup event */
|
||||
writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data);
|
||||
u32 value;
|
||||
|
||||
if (data->hwirq == ULONG_MAX)
|
||||
return 0;
|
||||
|
||||
value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq));
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
value |= WAKE_AOWAKE_CNTRL_LEVEL;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
value &= ~WAKE_AOWAKE_CNTRL_LEVEL;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING:
|
||||
value ^= WAKE_AOWAKE_CNTRL_LEVEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pmc_irq_init(struct tegra_pmc *pmc)
|
||||
{
|
||||
struct irq_domain *parent = NULL;
|
||||
struct device_node *np;
|
||||
|
||||
np = of_irq_find_parent(pmc->dev->of_node);
|
||||
if (np) {
|
||||
parent = irq_find_host(np);
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
if (!parent)
|
||||
return 0;
|
||||
|
||||
pmc->irq.name = dev_name(pmc->dev);
|
||||
pmc->irq.irq_mask = irq_chip_mask_parent;
|
||||
pmc->irq.irq_unmask = irq_chip_unmask_parent;
|
||||
pmc->irq.irq_eoi = irq_chip_eoi_parent;
|
||||
pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent;
|
||||
pmc->irq.irq_set_type = tegra_pmc_irq_set_type;
|
||||
pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake;
|
||||
|
||||
pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node,
|
||||
&tegra_pmc_irq_domain_ops, pmc);
|
||||
if (!pmc->domain) {
|
||||
dev_err(pmc->dev, "failed to allocate domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *base;
|
||||
|
|
@ -1610,6 +1892,8 @@ static int tegra_pmc_probe(struct platform_device *pdev)
|
|||
|
||||
tegra_pmc_init_tsense_reset(pmc);
|
||||
|
||||
tegra_pmc_reset_sysfs_init(pmc);
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
|
||||
err = tegra_powergate_debugfs_init();
|
||||
if (err < 0)
|
||||
|
|
@ -1627,6 +1911,10 @@ static int tegra_pmc_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
goto cleanup_restart_handler;
|
||||
|
||||
err = tegra_pmc_irq_init(pmc);
|
||||
if (err < 0)
|
||||
goto cleanup_restart_handler;
|
||||
|
||||
mutex_lock(&pmc->powergates_lock);
|
||||
iounmap(pmc->base);
|
||||
pmc->base = base;
|
||||
|
|
@ -1676,6 +1964,11 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = {
|
|||
.dpd_status = 0x1bc,
|
||||
.dpd2_req = 0x1c0,
|
||||
.dpd2_status = 0x1c4,
|
||||
.rst_status = 0x1b4,
|
||||
.rst_source_shift = 0x0,
|
||||
.rst_source_mask = 0x7,
|
||||
.rst_level_shift = 0x0,
|
||||
.rst_level_mask = 0x0,
|
||||
};
|
||||
|
||||
static void tegra20_pmc_init(struct tegra_pmc *pmc)
|
||||
|
|
@ -1733,6 +2026,10 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
|
|||
.regs = &tegra20_pmc_regs,
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = NULL,
|
||||
.num_reset_sources = 0,
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
|
||||
static const char * const tegra30_powergates[] = {
|
||||
|
|
@ -1774,6 +2071,10 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
|
|||
.regs = &tegra20_pmc_regs,
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
|
||||
static const char * const tegra114_powergates[] = {
|
||||
|
|
@ -1819,6 +2120,10 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
|
|||
.regs = &tegra20_pmc_regs,
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
|
||||
static const char * const tegra124_powergates[] = {
|
||||
|
|
@ -1924,6 +2229,10 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
|
|||
.regs = &tegra20_pmc_regs,
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
|
||||
static const char * const tegra210_powergates[] = {
|
||||
|
|
@ -2025,6 +2334,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
|
|||
.regs = &tegra20_pmc_regs,
|
||||
.init = tegra20_pmc_init,
|
||||
.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra30_reset_sources,
|
||||
.num_reset_sources = 5,
|
||||
.reset_levels = NULL,
|
||||
.num_reset_levels = 0,
|
||||
};
|
||||
|
||||
#define TEGRA186_IO_PAD_TABLE(_pad) \
|
||||
|
|
@ -2082,6 +2395,11 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = {
|
|||
.dpd_status = 0x78,
|
||||
.dpd2_req = 0x7c,
|
||||
.dpd2_status = 0x80,
|
||||
.rst_status = 0x70,
|
||||
.rst_source_shift = 0x2,
|
||||
.rst_source_mask = 0x3C,
|
||||
.rst_level_shift = 0x0,
|
||||
.rst_level_mask = 0x3,
|
||||
};
|
||||
|
||||
static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
|
||||
|
|
@ -2119,6 +2437,11 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
|
|||
iounmap(wake);
|
||||
}
|
||||
|
||||
static const struct tegra_wake_event tegra186_wake_events[] = {
|
||||
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA_AON_GPIO(FF, 0)),
|
||||
TEGRA_WAKE_IRQ("rtc", 73, 10),
|
||||
};
|
||||
|
||||
static const struct tegra_pmc_soc tegra186_pmc_soc = {
|
||||
.num_powergates = 0,
|
||||
.powergates = NULL,
|
||||
|
|
@ -2134,10 +2457,87 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
|
|||
.regs = &tegra186_pmc_regs,
|
||||
.init = NULL,
|
||||
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
|
||||
.reset_sources = tegra186_reset_sources,
|
||||
.num_reset_sources = 14,
|
||||
.reset_levels = tegra186_reset_levels,
|
||||
.num_reset_levels = 3,
|
||||
.num_wake_events = ARRAY_SIZE(tegra186_wake_events),
|
||||
.wake_events = tegra186_wake_events,
|
||||
};
|
||||
|
||||
static const struct tegra_io_pad_soc tegra194_io_pads[] = {
|
||||
{ .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_EQOS, .dpd = 8, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CLK2_BIAS, .dpd = 9, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 10, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_DAP3, .dpd = 11, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_DAP5, .dpd = 12, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PWR_CTL, .dpd = 15, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SOC_GPIO53, .dpd = 16, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_GP_PWM2, .dpd = 18, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_GP_PWM3, .dpd = 19, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SOC_GPIO12, .dpd = 20, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SOC_GPIO13, .dpd = 21, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SOC_GPIO10, .dpd = 22, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_UART4, .dpd = 23, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_UART5, .dpd = 24, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_HDMI_DP3, .dpd = 26, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_HDMI_DP2, .dpd = 27, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_CTL2, .dpd = 33, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_L0_RST_N, .dpd = 34, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_L1_RST_N, .dpd = 35, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_PEX_L5_RST_N, .dpd = 37, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSIG, .dpd = 50, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CSIH, .dpd = 51, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX },
|
||||
{ .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX },
|
||||
};
|
||||
|
||||
static const struct tegra_wake_event tegra194_wake_events[] = {
|
||||
TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)),
|
||||
TEGRA_WAKE_IRQ("rtc", 73, 10),
|
||||
};
|
||||
|
||||
static const struct tegra_pmc_soc tegra194_pmc_soc = {
|
||||
.num_powergates = 0,
|
||||
.powergates = NULL,
|
||||
.num_cpu_powergates = 0,
|
||||
.cpu_powergates = NULL,
|
||||
.has_tsense_reset = false,
|
||||
.has_gpu_clamps = false,
|
||||
.num_io_pads = ARRAY_SIZE(tegra194_io_pads),
|
||||
.io_pads = tegra194_io_pads,
|
||||
.regs = &tegra186_pmc_regs,
|
||||
.init = NULL,
|
||||
.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
|
||||
.num_wake_events = ARRAY_SIZE(tegra194_wake_events),
|
||||
.wake_events = tegra194_wake_events,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_pmc_match[] = {
|
||||
{ .compatible = "nvidia,tegra194-pmc", .data = &tegra186_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc },
|
||||
{ .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc },
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
static struct wkup_m3_ipc *m3_ipc_state;
|
||||
|
||||
static const struct wkup_m3_wakeup_src wakeups[] = {
|
||||
{.irq_nr = 16, .src = "PRCM"},
|
||||
{.irq_nr = 35, .src = "USB0_PHY"},
|
||||
{.irq_nr = 36, .src = "USB1_PHY"},
|
||||
{.irq_nr = 40, .src = "I2C0"},
|
||||
|
|
|
|||
Loading…
Reference in a new issue