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:
Linus Torvalds 2018-12-31 17:32:35 -08:00
commit d36377c6eb
68 changed files with 3910 additions and 668 deletions

View file

@ -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/

View file

@ -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

View file

@ -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

View 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);

View file

@ -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,

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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, },
{ }
};

View file

@ -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

View file

@ -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

View 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");

View file

@ -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"

View file

@ -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);

View file

@ -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");

View file

@ -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;

View file

@ -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");

View file

@ -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);

View file

@ -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 = {

View file

@ -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 },
};

View file

@ -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 = {

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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;
}

View file

@ -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 },

View file

@ -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"},