Commit 82483ad6 authored by Olof Johansson's avatar Olof Johansson

Merge tag 'tegra-for-3.20-soc' of...

Merge tag 'tegra-for-3.20-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/soc

Merge "ARM: tegra: Core code changes for v3.20" from Thierry Reding:

This contains a couple of preparatory patches for 64-bit support. A new
feature is implemented in the power-management controller which allows
it to switch off the SoC if it overheats.

* tag 'tegra-for-3.20-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  soc: tegra: Add thermal reset (thermtrip) support to PMC
  ARM: tegra: Add PMC thermtrip programming to Jetson TK1 device tree
  of: Add descriptions of thermtrip properties to Tegra PMC bindings
  soc/tegra: pmc: Add Tegra132 support
  soc/tegra: fuse: Add Tegra132 support
  soc/tegra: fuse: Constify tegra_fuse_info structures
  soc/tegra: Add Tegra132 support
  clocksource: Build Tegra timer on 32-bit ARM only
  soc/tegra: pmc: restrict compilation of suspend-related support to ARM
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 085dd64e 3568df3d
...@@ -47,6 +47,23 @@ Required properties when nvidia,suspend-mode=<0>: ...@@ -47,6 +47,23 @@ Required properties when nvidia,suspend-mode=<0>:
sleep mode, the warm boot code will restore some PLLs, clocks and then sleep mode, the warm boot code will restore some PLLs, clocks and then
bring up CPU0 for resuming the system. bring up CPU0 for resuming the system.
Hardware-triggered thermal reset:
On Tegra30, Tegra114 and Tegra124, if the 'i2c-thermtrip' subnode exists,
hardware-triggered thermal reset will be enabled.
Required properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'):
- nvidia,i2c-controller-id : ID of I2C controller to send poweroff command to. Valid values are
described in section 9.2.148 "APBDEV_PMC_SCRATCH53_0" of the
Tegra K1 Technical Reference Manual.
- nvidia,bus-addr : Bus address of the PMU on the I2C bus
- nvidia,reg-addr : I2C register address to write poweroff command to
- nvidia,reg-data : Poweroff command to write to PMU
Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'):
- nvidia,pinmux-id : Pinmux used by the hardware when issuing poweroff command.
Defaults to 0. Valid values are described in section 12.5.2
"Pinmux Support" of the Tegra4 Technical Reference Manual.
Example: Example:
/ SoC dts including file / SoC dts including file
...@@ -68,6 +85,15 @@ pmc@7000f400 { ...@@ -68,6 +85,15 @@ pmc@7000f400 {
/ Tegra board dts file / Tegra board dts file
{ {
...
pmc@7000f400 {
i2c-thermtrip {
nvidia,i2c-controller-id = <4>;
nvidia,bus-addr = <0x40>;
nvidia,reg-addr = <0x36>;
nvidia,reg-data = <0x2>;
};
};
... ...
clocks { clocks {
compatible = "simple-bus"; compatible = "simple-bus";
......
...@@ -1673,6 +1673,13 @@ pmc@0,7000e400 { ...@@ -1673,6 +1673,13 @@ pmc@0,7000e400 {
nvidia,core-pwr-off-time = <61036>; nvidia,core-pwr-off-time = <61036>;
nvidia,core-power-req-active-high; nvidia,core-power-req-active-high;
nvidia,sys-clock-req-active-high; nvidia,sys-clock-req-active-high;
i2c-thermtrip {
nvidia,i2c-controller-id = <4>;
nvidia,bus-addr = <0x40>;
nvidia,reg-addr = <0x36>;
nvidia,reg-data = <0x2>;
};
}; };
/* Serial ATA */ /* Serial ATA */
......
...@@ -27,6 +27,7 @@ config ARCH_TEGRA_2x_SOC ...@@ -27,6 +27,7 @@ config ARCH_TEGRA_2x_SOC
select PINCTRL_TEGRA20 select PINCTRL_TEGRA20
select PL310_ERRATA_727915 if CACHE_L2X0 select PL310_ERRATA_727915 if CACHE_L2X0
select PL310_ERRATA_769419 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0
select TEGRA_TIMER
help help
Support for NVIDIA Tegra AP20 and T20 processors, based on the Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
...@@ -37,6 +38,7 @@ config ARCH_TEGRA_3x_SOC ...@@ -37,6 +38,7 @@ config ARCH_TEGRA_3x_SOC
select ARM_ERRATA_764369 if SMP select ARM_ERRATA_764369 if SMP
select PINCTRL_TEGRA30 select PINCTRL_TEGRA30
select PL310_ERRATA_769419 if CACHE_L2X0 select PL310_ERRATA_769419 if CACHE_L2X0
select TEGRA_TIMER
help help
Support for NVIDIA Tegra T30 processor family, based on the Support for NVIDIA Tegra T30 processor family, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
...@@ -47,6 +49,7 @@ config ARCH_TEGRA_114_SOC ...@@ -47,6 +49,7 @@ config ARCH_TEGRA_114_SOC
select ARM_L1_CACHE_SHIFT_6 select ARM_L1_CACHE_SHIFT_6
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select PINCTRL_TEGRA114 select PINCTRL_TEGRA114
select TEGRA_TIMER
help help
Support for NVIDIA Tegra T114 processor family, based on the Support for NVIDIA Tegra T114 processor family, based on the
ARM CortexA15MP CPU ARM CortexA15MP CPU
...@@ -56,6 +59,7 @@ config ARCH_TEGRA_124_SOC ...@@ -56,6 +59,7 @@ config ARCH_TEGRA_124_SOC
select ARM_L1_CACHE_SHIFT_6 select ARM_L1_CACHE_SHIFT_6
select HAVE_ARM_ARCH_TIMER select HAVE_ARM_ARCH_TIMER
select PINCTRL_TEGRA124 select PINCTRL_TEGRA124
select TEGRA_TIMER
help help
Support for NVIDIA Tegra T124 processor family, based on the Support for NVIDIA Tegra T124 processor family, based on the
ARM CortexA15MP CPU ARM CortexA15MP CPU
......
...@@ -47,6 +47,9 @@ config SUN5I_HSTIMER ...@@ -47,6 +47,9 @@ config SUN5I_HSTIMER
select CLKSRC_MMIO select CLKSRC_MMIO
bool bool
config TEGRA_TIMER
bool
config VT8500_TIMER config VT8500_TIMER
bool bool
......
...@@ -27,7 +27,7 @@ obj-$(CONFIG_ARCH_U300) += timer-u300.o ...@@ -27,7 +27,7 @@ obj-$(CONFIG_ARCH_U300) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o
......
...@@ -81,6 +81,7 @@ static const struct of_device_id car_match[] __initconst = { ...@@ -81,6 +81,7 @@ static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra30-car", }, { .compatible = "nvidia,tegra30-car", },
{ .compatible = "nvidia,tegra114-car", }, { .compatible = "nvidia,tegra114-car", },
{ .compatible = "nvidia,tegra124-car", }, { .compatible = "nvidia,tegra124-car", },
{ .compatible = "nvidia,tegra132-car", },
{}, {},
}; };
......
...@@ -56,7 +56,7 @@ struct tegra_fuse_info { ...@@ -56,7 +56,7 @@ struct tegra_fuse_info {
static void __iomem *fuse_base; static void __iomem *fuse_base;
static struct clk *fuse_clk; static struct clk *fuse_clk;
static struct tegra_fuse_info *fuse_info; static const struct tegra_fuse_info *fuse_info;
u32 tegra30_fuse_readl(const unsigned int offset) u32 tegra30_fuse_readl(const unsigned int offset)
{ {
...@@ -78,18 +78,18 @@ u32 tegra30_fuse_readl(const unsigned int offset) ...@@ -78,18 +78,18 @@ u32 tegra30_fuse_readl(const unsigned int offset)
return val; return val;
} }
static struct tegra_fuse_info tegra30_info = { static const struct tegra_fuse_info tegra30_info = {
.size = 0x2a4, .size = 0x2a4,
.spare_bit = 0x144, .spare_bit = 0x144,
.speedo_idx = SPEEDO_TEGRA30, .speedo_idx = SPEEDO_TEGRA30,
}; };
static struct tegra_fuse_info tegra114_info = { static const struct tegra_fuse_info tegra114_info = {
.size = 0x2a0, .size = 0x2a0,
.speedo_idx = SPEEDO_TEGRA114, .speedo_idx = SPEEDO_TEGRA114,
}; };
static struct tegra_fuse_info tegra124_info = { static const struct tegra_fuse_info tegra124_info = {
.size = 0x300, .size = 0x300,
.speedo_idx = SPEEDO_TEGRA124, .speedo_idx = SPEEDO_TEGRA124,
}; };
...@@ -182,6 +182,7 @@ static void __init legacy_fuse_init(void) ...@@ -182,6 +182,7 @@ static void __init legacy_fuse_init(void)
fuse_info = &tegra114_info; fuse_info = &tegra114_info;
break; break;
case TEGRA124: case TEGRA124:
case TEGRA132:
fuse_info = &tegra124_info; fuse_info = &tegra124_info;
break; break;
default: default:
......
...@@ -70,6 +70,10 @@ ...@@ -70,6 +70,10 @@
#define PMC_SCRATCH41 0x140 #define PMC_SCRATCH41 0x140
#define PMC_SENSOR_CTRL 0x1b0
#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2)
#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
#define IO_DPD_REQ 0x1b8 #define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30) #define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30) #define IO_DPD_REQ_CODE_OFF (1 << 30)
...@@ -81,6 +85,18 @@ ...@@ -81,6 +85,18 @@
#define IO_DPD2_STATUS 0x1c4 #define IO_DPD2_STATUS 0x1c4
#define SEL_DPD_TIM 0x1c8 #define SEL_DPD_TIM 0x1c8
#define PMC_SCRATCH54 0x258
#define PMC_SCRATCH54_DATA_SHIFT 8
#define PMC_SCRATCH54_ADDR_SHIFT 0
#define PMC_SCRATCH55 0x25c
#define PMC_SCRATCH55_RESET_TEGRA (1 << 31)
#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
#define PMC_SCRATCH55_PINMUX_SHIFT 24
#define PMC_SCRATCH55_16BITOP (1 << 15)
#define PMC_SCRATCH55_CHECKSUM_SHIFT 16
#define PMC_SCRATCH55_I2CSLV1_SHIFT 0
#define GPU_RG_CNTRL 0x2d4 #define GPU_RG_CNTRL 0x2d4
struct tegra_pmc_soc { struct tegra_pmc_soc {
...@@ -88,6 +104,9 @@ struct tegra_pmc_soc { ...@@ -88,6 +104,9 @@ struct tegra_pmc_soc {
const char *const *powergates; const char *const *powergates;
unsigned int num_cpu_powergates; unsigned int num_cpu_powergates;
const u8 *cpu_powergates; const u8 *cpu_powergates;
bool has_tsense_reset;
bool has_gpu_clamps;
}; };
/** /**
...@@ -110,6 +129,7 @@ struct tegra_pmc_soc { ...@@ -110,6 +129,7 @@ struct tegra_pmc_soc {
* @powergates_lock: mutex for power gate register access * @powergates_lock: mutex for power gate register access
*/ */
struct tegra_pmc { struct tegra_pmc {
struct device *dev;
void __iomem *base; void __iomem *base;
struct clk *clk; struct clk *clk;
...@@ -225,11 +245,11 @@ int tegra_powergate_remove_clamping(int id) ...@@ -225,11 +245,11 @@ int tegra_powergate_remove_clamping(int id)
return -EINVAL; return -EINVAL;
/* /*
* The Tegra124 GPU has a separate register (with different semantics) * On Tegra124 and later, the clamps for the GPU are controlled by a
* to remove clamps. * separate register (with different semantics).
*/ */
if (tegra_get_chip_id() == TEGRA124) { if (id == TEGRA_POWERGATE_3D) {
if (id == TEGRA_POWERGATE_3D) { if (pmc->soc->has_gpu_clamps) {
tegra_pmc_writel(0, GPU_RG_CNTRL); tegra_pmc_writel(0, GPU_RG_CNTRL);
return 0; return 0;
} }
...@@ -703,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc) ...@@ -703,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc)
tegra_pmc_writel(value, PMC_CNTRL); tegra_pmc_writel(value, PMC_CNTRL);
} }
void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
{
static const char disabled[] = "emergency thermal reset disabled";
u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux;
struct device *dev = pmc->dev;
struct device_node *np;
u32 value, checksum;
if (!pmc->soc->has_tsense_reset)
goto out;
np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
if (!np) {
dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) {
dev_err(dev, "I2C controller ID missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) {
dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,reg-addr", &reg_addr)) {
dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,reg-data", &reg_data)) {
dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled);
goto out;
}
if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux))
pinmux = 0;
value = tegra_pmc_readl(PMC_SENSOR_CTRL);
value |= PMC_SENSOR_CTRL_SCRATCH_WRITE;
tegra_pmc_writel(value, PMC_SENSOR_CTRL);
value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) |
(reg_addr << PMC_SCRATCH54_ADDR_SHIFT);
tegra_pmc_writel(value, PMC_SCRATCH54);
value = PMC_SCRATCH55_RESET_TEGRA;
value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT;
value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT;
value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT;
/*
* Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will
* contain the checksum and are currently zero, so they are not added.
*/
checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff)
+ ((value >> 24) & 0xff);
checksum &= 0xff;
checksum = 0x100 - checksum;
value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT;
tegra_pmc_writel(value, PMC_SCRATCH55);
value = tegra_pmc_readl(PMC_SENSOR_CTRL);
value |= PMC_SENSOR_CTRL_ENABLE_RST;
tegra_pmc_writel(value, PMC_SENSOR_CTRL);
dev_info(pmc->dev, "emergency thermal reset enabled\n");
out:
of_node_put(np);
return;
}
static int tegra_pmc_probe(struct platform_device *pdev) static int tegra_pmc_probe(struct platform_device *pdev)
{ {
void __iomem *base = pmc->base; void __iomem *base = pmc->base;
...@@ -728,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev) ...@@ -728,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return err; return err;
} }
pmc->dev = &pdev->dev;
tegra_pmc_init(pmc); tegra_pmc_init(pmc);
tegra_pmc_init_tsense_reset(pmc);
if (IS_ENABLED(CONFIG_DEBUG_FS)) { if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_powergate_debugfs_init(); err = tegra_powergate_debugfs_init();
if (err < 0) if (err < 0)
...@@ -739,7 +840,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) ...@@ -739,7 +840,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
static int tegra_pmc_suspend(struct device *dev) static int tegra_pmc_suspend(struct device *dev)
{ {
tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41); tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
...@@ -753,10 +854,11 @@ static int tegra_pmc_resume(struct device *dev) ...@@ -753,10 +854,11 @@ static int tegra_pmc_resume(struct device *dev)
return 0; return 0;
} }
#endif
static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
#endif
static const char * const tegra20_powergates[] = { static const char * const tegra20_powergates[] = {
[TEGRA_POWERGATE_CPU] = "cpu", [TEGRA_POWERGATE_CPU] = "cpu",
[TEGRA_POWERGATE_3D] = "3d", [TEGRA_POWERGATE_3D] = "3d",
...@@ -772,6 +874,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { ...@@ -772,6 +874,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.powergates = tegra20_powergates, .powergates = tegra20_powergates,
.num_cpu_powergates = 0, .num_cpu_powergates = 0,
.cpu_powergates = NULL, .cpu_powergates = NULL,
.has_tsense_reset = false,
.has_gpu_clamps = false,
}; };
static const char * const tegra30_powergates[] = { static const char * const tegra30_powergates[] = {
...@@ -803,6 +907,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { ...@@ -803,6 +907,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.powergates = tegra30_powergates, .powergates = tegra30_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
.cpu_powergates = tegra30_cpu_powergates, .cpu_powergates = tegra30_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false,
}; };
static const char * const tegra114_powergates[] = { static const char * const tegra114_powergates[] = {
...@@ -838,6 +944,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { ...@@ -838,6 +944,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.powergates = tegra114_powergates, .powergates = tegra114_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates), .num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
.cpu_powergates = tegra114_cpu_powergates, .cpu_powergates = tegra114_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = false,
}; };
static const char * const tegra124_powergates[] = { static const char * const tegra124_powergates[] = {
...@@ -879,6 +987,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { ...@@ -879,6 +987,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.powergates = tegra124_powergates, .powergates = tegra124_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates), .num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
.cpu_powergates = tegra124_cpu_powergates, .cpu_powergates = tegra124_cpu_powergates,
.has_tsense_reset = true,
.has_gpu_clamps = true,
}; };
static const struct of_device_id tegra_pmc_match[] = { static const struct of_device_id tegra_pmc_match[] = {
...@@ -894,7 +1004,9 @@ static struct platform_driver tegra_pmc_driver = { ...@@ -894,7 +1004,9 @@ static struct platform_driver tegra_pmc_driver = {
.name = "tegra-pmc", .name = "tegra-pmc",
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
.of_match_table = tegra_pmc_match, .of_match_table = tegra_pmc_match,
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
.pm = &tegra_pmc_pm_ops, .pm = &tegra_pmc_pm_ops,
#endif
}, },
.probe = tegra_pmc_probe, .probe = tegra_pmc_probe,
}; };
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define TEGRA30 0x30 #define TEGRA30 0x30
#define TEGRA114 0x35 #define TEGRA114 0x35
#define TEGRA124 0x40 #define TEGRA124 0x40
#define TEGRA132 0x13
#define TEGRA_FUSE_SKU_CALIB_0 0xf0 #define TEGRA_FUSE_SKU_CALIB_0 0xf0
#define TEGRA30_FUSE_SATA_CALIB 0x124 #define TEGRA30_FUSE_SATA_CALIB 0x124
......
...@@ -17,7 +17,7 @@ enum tegra_suspend_mode { ...@@ -17,7 +17,7 @@ enum tegra_suspend_mode {
TEGRA_MAX_SUSPEND_MODE, TEGRA_MAX_SUSPEND_MODE,
}; };
#ifdef CONFIG_PM_SLEEP #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
enum tegra_suspend_mode enum tegra_suspend_mode
tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode); tegra_pm_validate_suspend_mode(enum tegra_suspend_mode mode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment