1
0
Files
Greg Kroah-Hartman b16ff0ab99 Merge 4.9.229 into android-4.9-q
Changes in 4.9.229
	power: supply: bq24257_charger: Replace depends on REGMAP_I2C with select
	clk: sunxi: Fix incorrect usage of round_down()
	i2c: piix4: Detect secondary SMBus controller on AMD AM4 chipsets
	iio: pressure: bmp280: Tolerate IRQ before registering
	clk: qcom: msm8916: Fix the address location of pll->config_reg
	backlight: lp855x: Ensure regulators are disabled on probe failure
	ARM: integrator: Add some Kconfig selections
	ALSA: isa/wavefront: prevent out of bounds write in ioctl
	scsi: qla2xxx: Fix issue with adapter's stopping state
	iio: bmp280: fix compensation of humidity
	i2c: pxa: clear all master action bits in i2c_pxa_stop_message()
	usblp: poison URBs upon disconnect
	PCI: aardvark: Don't blindly enable ASPM L0s and don't write to read-only register
	ps3disk: use the default segment boundary
	vfio/pci: fix memory leaks in alloc_perm_bits()
	mfd: wm8994: Fix driver operation if loaded as modules
	scsi: lpfc: Fix lpfc_nodelist leak when processing unsolicited event
	clk: clk-flexgen: fix clock-critical handling
	powerpc/perf/hv-24x7: Fix inconsistent output values incase multiple hv-24x7 events run
	nfsd: Fix svc_xprt refcnt leak when setup callback client failed
	powerpc/crashkernel: Take "mem=" option into account
	yam: fix possible memory leak in yam_init_driver
	mksysmap: Fix the mismatch of '.L' symbols in System.map
	scsi: sr: Fix sr_probe() missing deallocate of device minor
	scsi: ibmvscsi: Don't send host info in adapter info MAD after LPM
	ALSA: usb-audio: Improve frames size computation
	s390/qdio: put thinint indicator after early error
	tty: hvc: Fix data abort due to race in hvc_open
	staging: sm750fb: add missing case while setting FB_VISUAL
	i2c: pxa: fix i2c_pxa_scream_blue_murder() debug output
	serial: amba-pl011: Make sure we initialize the port.lock spinlock
	drivers: base: Fix NULL pointer exception in __platform_driver_probe() if a driver developer is foolish
	PCI: rcar: Fix incorrect programming of OB windows
	PCI/ASPM: Allow ASPM on links to PCIe-to-PCI/PCI-X Bridges
	power: supply: lp8788: Fix an error handling path in 'lp8788_charger_probe()'
	power: supply: smb347-charger: IRQSTAT_D is volatile
	scsi: mpt3sas: Fix double free warnings
	dlm: remove BUG() before panic()
	clk: ti: composite: fix memory leak
	tty: n_gsm: Fix SOF skipping
	tty: n_gsm: Fix waking up upper tty layer when room available
	powerpc/pseries/ras: Fix FWNMI_VALID off by one
	powerpc/ps3: Fix kexec shutdown hang
	vfio-pci: Mask cap zero
	usb/ohci-platform: Fix a warning when hibernating
	drm/msm/mdp5: Fix mdp5_init error path for failed mdp5_kms allocation
	USB: host: ehci-mxc: Add error handling in ehci_mxc_drv_probe()
	tty: n_gsm: Fix bogus i++ in gsm_data_kick
	clk: samsung: exynos5433: Add IGNORE_UNUSED flag to sclk_i2s1
	powerpc/64s/pgtable: fix an undefined behaviour
	PCI/PTM: Inherit Switch Downstream Port PTM settings from Upstream Port
	IB/cma: Fix ports memory leak in cma_configfs
	watchdog: da9062: No need to ping manually before setting timeout
	usb: dwc2: gadget: move gadget resume after the core is in L0 state
	USB: gadget: udc: s3c2410_udc: Remove pointless NULL check in s3c2410_udc_nuke
	usb: gadget: lpc32xx_udc: don't dereference ep pointer before null check
	usb: gadget: fix potential double-free in m66592_probe.
	usb: gadget: Fix issue with config_ep_by_speed function
	clk: bcm2835: Fix return type of bcm2835_register_gate
	net: sunrpc: Fix off-by-one issues in 'rpc_ntop6'
	NFSv4.1 fix rpc_call_done assignment for BIND_CONN_TO_SESSION
	extcon: adc-jack: Fix an error handling path in 'adc_jack_probe()'
	ASoC: fsl_asrc_dma: Fix dma_chan leak when config DMA channel failed
	openrisc: Fix issue with argument clobbering for clone/fork
	gfs2: Allow lock_nolock mount to specify jid=X
	scsi: iscsi: Fix reference count leak in iscsi_boot_create_kobj
	pinctrl: imxl: Fix an error handling path in 'imx1_pinctrl_core_probe()'
	crypto: omap-sham - add proper load balancing support for multicore
	lib/zlib: remove outdated and incorrect pre-increment optimization
	include/linux/bitops.h: avoid clang shift-count-overflow warnings
	elfnote: mark all .note sections SHF_ALLOC
	selftests/vm/pkeys: fix alloc_random_pkey() to make it really random
	selftests/net: in timestamping, strncpy needs to preserve null byte
	scsi: acornscsi: Fix an error handling path in acornscsi_probe()
	usb/xhci-plat: Set PM runtime as active on resume
	usb/ehci-platform: Set PM runtime as active on resume
	perf report: Fix NULL pointer dereference in hists__fprintf_nr_sample_events()
	bcache: fix potential deadlock problem in btree_gc_coalesce
	block: Fix use-after-free in blkdev_get()
	libata: Use per port sync for detach
	drm: encoder_slave: fix refcouting error for modules
	drm/dp_mst: Reformat drm_dp_check_act_status() a bit
	drm/qxl: Use correct notify port address when creating cursor ring
	selinux: fix double free
	ext4: fix partial cluster initialization when splitting extent
	drm/dp_mst: Increase ACT retry timeout to 3s
	x86/boot/compressed: Relax sed symbol type regex for LLVM ld.lld
	block: nr_sects_write(): Disable preemption on seqcount write
	s390: fix syscall_get_error for compat processes
	drm/i915: Whitelist context-local timestamp in the gen9 cmdparser
	crypto: algboss - don't wait during notifier callback
	kprobes: Fix to protect kick_kprobe_optimizer() by kprobe_mutex
	powerpc/kprobes: Fixes for kprobe_lookup_name() on BE
	x86/kprobes: Avoid kretprobe recursion bug
	kretprobe: Prevent triggering kretprobe from within kprobe_flush_task
	e1000e: Do not wake up the system via WOL if device wakeup is disabled
	sched/rt, net: Use CONFIG_PREEMPTION.patch
	net: core: device_rename: Use rwsem instead of a seqcount
	media: dvb_frontend: initialize variable s with FE_NONE instead of 0
	media: dvb/frontend.h: move out a private internal structure
	media: dvb/frontend.h: document the uAPI file
	media: dvb_frontend: get rid of get_property() callback
	media: stv0288: get rid of set_property boilerplate
	media: stv6110: get rid of a srate dead code
	media: friio-fe: get rid of set_property()
	media: dvb_frontend: get rid of set_property() callback
	media: dvb_frontend: cleanup dvb_frontend_ioctl_properties()
	media: dvb_frontend: cleanup ioctl handling logic
	media: dvb_frontend: get rid of property cache's state
	media: dvb_frontend: better document the -EPERM condition
	media: dvb_frontend: fix return values for FE_SET_PROPERTY
	media: dvb_frontend: dtv_property_process_set() cleanups
	media: dvb_frontend: be sure to init dvb_frontend_handle_ioctl() return code
	media: dvb_frontend: Add unlocked_ioctl in dvb_frontend.c
	media: dvb_frontend: Add compat_ioctl callback
	media: dvb_frontend: Add commands implementation for compat ioct
	media: dvb_frontend: fix wrong cast in compat_ioctl
	media: dvb_frontend: fix return error code
	mtd: rawnand: Pass a nand_chip object to nand_release()
	mtd: rawnand: diskonchip: Fix the probe error path
	mtd: rawnand: sharpsl: Fix the probe error path
	mtd: rawnand: xway: Fix the probe error path
	mtd: rawnand: orion: Fix the probe error path
	mtd: rawnand: socrates: Fix the probe error path
	mtd: rawnand: plat_nand: Fix the probe error path
	mtd: rawnand: mtk: Fix the probe error path
	mtd: rawnand: tmio: Fix the probe error path
	scsi: scsi_devinfo: handle non-terminated strings
	l2tp: Allow duplicate session creation with UDP
	net: sched: export __netdev_watchdog_up()
	fix a braino in "sparc32: fix register window handling in genregs32_[gs]et()"
	mld: fix memory leak in ipv6_mc_destroy_dev()
	net: fix memleak in register_netdevice()
	net: usb: ax88179_178a: fix packet alignment padding
	rocker: fix incorrect error handling in dma_rings_init
	rxrpc: Fix notification call on completion of discarded calls
	tg3: driver sleeps indefinitely when EEH errors exceed eeh_max_freezes
	ip_tunnel: fix use-after-free in ip_tunnel_lookup()
	tcp_cubic: fix spurious HYSTART_DELAY exit upon drop in min RTT
	ip6_gre: fix use-after-free in ip6gre_tunnel_lookup()
	tcp: grow window for OOO packets only for SACK flows
	sctp: Don't advertise IPv4 addresses if ipv6only is set on the socket
	net: Fix the arp error in some cases
	net: Do not clear the sock TX queue in sk_set_socket()
	net: core: reduce recursion limit value
	USB: ohci-sm501: Add missed iounmap() in remove
	usb: dwc2: Postponed gadget registration to the udc class driver
	usb: add USB_QUIRK_DELAY_INIT for Logitech C922
	USB: ehci: reopen solution for Synopsys HC bug
	usb: host: ehci-exynos: Fix error check in exynos_ehci_probe()
	ALSA: usb-audio: add quirk for Denon DCD-1500RE
	xhci: Fix incorrect EP_STATE_MASK
	xhci: Fix enumeration issue when setting max packet size for FS devices.
	cdc-acm: Add DISABLE_ECHO quirk for Microchip/SMSC chip
	ALSA: usb-audio: uac1: Invalidate ctl on interrupt
	ALSA: usb-audio: Clean up mixer element list traverse
	ALSA: usb-audio: Fix OOB access of mixer element list
	xhci: Poll for U0 after disabling USB2 LPM
	cifs/smb3: Fix data inconsistent when punch hole
	cifs/smb3: Fix data inconsistent when zero file range
	efi/esrt: Fix reference count leak in esre_create_sysfs_entry.
	RDMA/mad: Fix possible memory leak in ib_mad_post_receive_mads()
	net: qed: fix left elements count calculation
	net: qed: fix NVMe login fails over VFs
	net: qed: fix excessive QM ILT lines consumption
	ARM: imx5: add missing put_device() call in imx_suspend_alloc_ocram()
	usb: gadget: udc: Potential Oops in error handling code
	netfilter: ipset: fix unaligned atomic access
	sched/core: Fix PI boosting between RT and DEADLINE tasks
	ata/libata: Fix usage of page address by page_address in ata_scsi_mode_select_xlat function
	net: alx: fix race condition in alx_remove
	s390/ptrace: fix setting syscall number
	kbuild: improve cc-option to clean up all temporary files
	blktrace: break out of blktrace setup on concurrent calls
	ALSA: hda: Add NVIDIA codec IDs 9a & 9d through a0 to patch table
	ACPI: sysfs: Fix pm_profile_attr type
	KVM: X86: Fix MSR range of APIC registers in X2APIC mode
	mm/slab: use memzero_explicit() in kzfree()
	ocfs2: load global_inode_alloc
	ocfs2: fix value of OCFS2_INVALID_SLOT
	ocfs2: fix panic on nfs server over ocfs2
	arm64: perf: Report the PC value in REGS_ABI_32 mode
	tracing: Fix event trigger to accept redundant spaces
	drm/radeon: fix fb_div check in ni_init_smc_spll_table()
	sunrpc: fixed rollback in rpc_gssd_dummy_populate()
	SUNRPC: Properly set the @subbuf parameter of xdr_buf_subsegment()
	pNFS/flexfiles: Fix list corruption if the mirror count changes
	NFSv4 fix CLOSE not waiting for direct IO compeletion
	xfs: add agf freeblocks verify in xfs_agf_verify
	Revert "tty: hvc: Fix data abort due to race in hvc_open"
	Linux 4.9.229

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I0ce84c8f4c2c437fee36399c358c3dcc19fdfc1d
2020-07-09 21:01:12 +03:00

427 lines
11 KiB
C

/*
* Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/suspend.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/genalloc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <asm/cacheflush.h>
#include <asm/fncpy.h>
#include <asm/system_misc.h>
#include <asm/tlbflush.h>
#include "common.h"
#include "cpuidle.h"
#include "hardware.h"
#define MXC_CCM_CLPCR 0x54
#define MXC_CCM_CLPCR_LPM_OFFSET 0
#define MXC_CCM_CLPCR_LPM_MASK 0x3
#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET 9
#define MXC_CCM_CLPCR_VSTBY (0x1 << 8)
#define MXC_CCM_CLPCR_SBYOS (0x1 << 6)
#define MXC_CORTEXA8_PLAT_LPC 0xc
#define MXC_CORTEXA8_PLAT_LPC_DSM (1 << 0)
#define MXC_CORTEXA8_PLAT_LPC_DBG_DSM (1 << 1)
#define MXC_SRPG_NEON_SRPGCR 0x280
#define MXC_SRPG_ARM_SRPGCR 0x2a0
#define MXC_SRPG_EMPGC0_SRPGCR 0x2c0
#define MXC_SRPG_EMPGC1_SRPGCR 0x2d0
#define MXC_SRPGCR_PCR 1
/*
* The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
* This is also the lowest power state possible without affecting
* non-cpu parts of the system. For these reasons, imx5 should default
* to always using this state for cpu idling. The PM_SUSPEND_STANDBY also
* uses this state and needs to take no action when registers remain confgiured
* for this state.
*/
#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
struct imx5_suspend_io_state {
u32 offset;
u32 clear;
u32 set;
u32 saved_value;
};
struct imx5_pm_data {
phys_addr_t ccm_addr;
phys_addr_t cortex_addr;
phys_addr_t gpc_addr;
phys_addr_t m4if_addr;
phys_addr_t iomuxc_addr;
void (*suspend_asm)(void __iomem *ocram_vbase);
const u32 *suspend_asm_sz;
const struct imx5_suspend_io_state *suspend_io_config;
int suspend_io_count;
};
static const struct imx5_suspend_io_state imx53_suspend_io_config[] = {
#define MX53_DSE_HIGHZ_MASK (0x7 << 19)
{.offset = 0x584, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM0 */
{.offset = 0x594, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM1 */
{.offset = 0x560, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM2 */
{.offset = 0x554, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM3 */
{.offset = 0x574, .clear = MX53_DSE_HIGHZ_MASK}, /* CAS */
{.offset = 0x588, .clear = MX53_DSE_HIGHZ_MASK}, /* RAS */
{.offset = 0x578, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_0 */
{.offset = 0x570, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_1 */
{.offset = 0x580, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT0 */
{.offset = 0x564, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT1 */
{.offset = 0x57c, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS0 */
{.offset = 0x590, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS1 */
{.offset = 0x568, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS2 */
{.offset = 0x558, .clear = MX53_DSE_HIGHZ_MASK}, /* SDSQ3 */
{.offset = 0x6f0, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_ADDS */
{.offset = 0x718, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_BODS */
{.offset = 0x71c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B1DS */
{.offset = 0x728, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B2DS */
{.offset = 0x72c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B3DS */
/* Controls the CKE signal which is required to leave self refresh */
{.offset = 0x720, .clear = MX53_DSE_HIGHZ_MASK, .set = 1 << 19}, /* CTLDS */
};
static const struct imx5_pm_data imx51_pm_data __initconst = {
.ccm_addr = 0x73fd4000,
.cortex_addr = 0x83fa0000,
.gpc_addr = 0x73fd8000,
};
static const struct imx5_pm_data imx53_pm_data __initconst = {
.ccm_addr = 0x53fd4000,
.cortex_addr = 0x63fa0000,
.gpc_addr = 0x53fd8000,
.m4if_addr = 0x63fd8000,
.iomuxc_addr = 0x53fa8000,
.suspend_asm = &imx53_suspend,
.suspend_asm_sz = &imx53_suspend_sz,
.suspend_io_config = imx53_suspend_io_config,
.suspend_io_count = ARRAY_SIZE(imx53_suspend_io_config),
};
#define MX5_MAX_SUSPEND_IOSTATE ARRAY_SIZE(imx53_suspend_io_config)
/*
* This structure is for passing necessary data for low level ocram
* suspend code(arch/arm/mach-imx/suspend-imx53.S), if this struct
* definition is changed, the offset definition in that file
* must be also changed accordingly otherwise, the suspend to ocram
* function will be broken!
*/
struct imx5_cpu_suspend_info {
void __iomem *m4if_base;
void __iomem *iomuxc_base;
u32 io_count;
struct imx5_suspend_io_state io_state[MX5_MAX_SUSPEND_IOSTATE];
} __aligned(8);
static void __iomem *ccm_base;
static void __iomem *cortex_base;
static void __iomem *gpc_base;
static void __iomem *suspend_ocram_base;
static void (*imx5_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
/*
* set cpu low power mode before WFI instruction. This function is called
* mx5 because it can be used for mx51, and mx53.
*/
static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
{
u32 plat_lpc, arm_srpgcr, ccm_clpcr;
u32 empgc0, empgc1;
int stop_mode = 0;
/* always allow platform to issue a deep sleep mode request */
plat_lpc = imx_readl(cortex_base + MXC_CORTEXA8_PLAT_LPC) &
~(MXC_CORTEXA8_PLAT_LPC_DSM);
ccm_clpcr = imx_readl(ccm_base + MXC_CCM_CLPCR) &
~(MXC_CCM_CLPCR_LPM_MASK);
arm_srpgcr = imx_readl(gpc_base + MXC_SRPG_ARM_SRPGCR) &
~(MXC_SRPGCR_PCR);
empgc0 = imx_readl(gpc_base + MXC_SRPG_EMPGC0_SRPGCR) &
~(MXC_SRPGCR_PCR);
empgc1 = imx_readl(gpc_base + MXC_SRPG_EMPGC1_SRPGCR) &
~(MXC_SRPGCR_PCR);
switch (mode) {
case WAIT_CLOCKED:
break;
case WAIT_UNCLOCKED:
ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
break;
case WAIT_UNCLOCKED_POWER_OFF:
case STOP_POWER_OFF:
plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
| MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
if (mode == WAIT_UNCLOCKED_POWER_OFF) {
ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
stop_mode = 0;
} else {
ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
stop_mode = 1;
}
arm_srpgcr |= MXC_SRPGCR_PCR;
break;
case STOP_POWER_ON:
ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
break;
default:
printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
return;
}
imx_writel(plat_lpc, cortex_base + MXC_CORTEXA8_PLAT_LPC);
imx_writel(ccm_clpcr, ccm_base + MXC_CCM_CLPCR);
imx_writel(arm_srpgcr, gpc_base + MXC_SRPG_ARM_SRPGCR);
imx_writel(arm_srpgcr, gpc_base + MXC_SRPG_NEON_SRPGCR);
if (stop_mode) {
empgc0 |= MXC_SRPGCR_PCR;
empgc1 |= MXC_SRPGCR_PCR;
imx_writel(empgc0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
imx_writel(empgc1, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
}
}
static int mx5_suspend_enter(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_MEM:
mx5_cpu_lp_set(STOP_POWER_OFF);
break;
case PM_SUSPEND_STANDBY:
/* DEFAULT_IDLE_STATE already configured */
break;
default:
return -EINVAL;
}
if (state == PM_SUSPEND_MEM) {
local_flush_tlb_all();
flush_cache_all();
/*clear the EMPGC0/1 bits */
imx_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
imx_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
if (imx5_suspend_in_ocram_fn)
imx5_suspend_in_ocram_fn(suspend_ocram_base);
else
cpu_do_idle();
} else {
cpu_do_idle();
}
/* return registers to default idle state */
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
return 0;
}
static int mx5_pm_valid(suspend_state_t state)
{
return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
}
static const struct platform_suspend_ops mx5_suspend_ops = {
.valid = mx5_pm_valid,
.enter = mx5_suspend_enter,
};
static inline int imx5_cpu_do_idle(void)
{
int ret = tzic_enable_wake();
if (likely(!ret))
cpu_do_idle();
return ret;
}
static void imx5_pm_idle(void)
{
imx5_cpu_do_idle();
}
static int __init imx_suspend_alloc_ocram(
size_t size,
void __iomem **virt_out,
phys_addr_t *phys_out)
{
struct device_node *node;
struct platform_device *pdev;
struct gen_pool *ocram_pool;
unsigned long ocram_base;
void __iomem *virt;
phys_addr_t phys;
int ret = 0;
/* Copied from imx6: TODO factorize */
node = of_find_compatible_node(NULL, NULL, "mmio-sram");
if (!node) {
pr_warn("%s: failed to find ocram node!\n", __func__);
return -ENODEV;
}
pdev = of_find_device_by_node(node);
if (!pdev) {
pr_warn("%s: failed to find ocram device!\n", __func__);
ret = -ENODEV;
goto put_node;
}
ocram_pool = gen_pool_get(&pdev->dev, NULL);
if (!ocram_pool) {
pr_warn("%s: ocram pool unavailable!\n", __func__);
ret = -ENODEV;
goto put_device;
}
ocram_base = gen_pool_alloc(ocram_pool, size);
if (!ocram_base) {
pr_warn("%s: unable to alloc ocram!\n", __func__);
ret = -ENOMEM;
goto put_device;
}
phys = gen_pool_virt_to_phys(ocram_pool, ocram_base);
virt = __arm_ioremap_exec(phys, size, false);
if (phys_out)
*phys_out = phys;
if (virt_out)
*virt_out = virt;
put_device:
put_device(&pdev->dev);
put_node:
of_node_put(node);
return ret;
}
static int __init imx5_suspend_init(const struct imx5_pm_data *soc_data)
{
struct imx5_cpu_suspend_info *suspend_info;
int ret;
/* Need this to avoid compile error due to const typeof in fncpy.h */
void (*suspend_asm)(void __iomem *) = soc_data->suspend_asm;
if (!suspend_asm)
return 0;
if (!soc_data->suspend_asm_sz || !*soc_data->suspend_asm_sz)
return -EINVAL;
ret = imx_suspend_alloc_ocram(
*soc_data->suspend_asm_sz + sizeof(*suspend_info),
&suspend_ocram_base, NULL);
if (ret)
return ret;
suspend_info = suspend_ocram_base;
suspend_info->io_count = soc_data->suspend_io_count;
memcpy(suspend_info->io_state, soc_data->suspend_io_config,
sizeof(*suspend_info->io_state) * soc_data->suspend_io_count);
suspend_info->m4if_base = ioremap(soc_data->m4if_addr, SZ_16K);
if (!suspend_info->m4if_base) {
ret = -ENOMEM;
goto failed_map_m4if;
}
suspend_info->iomuxc_base = ioremap(soc_data->iomuxc_addr, SZ_16K);
if (!suspend_info->iomuxc_base) {
ret = -ENOMEM;
goto failed_map_iomuxc;
}
imx5_suspend_in_ocram_fn = fncpy(
suspend_ocram_base + sizeof(*suspend_info),
suspend_asm,
*soc_data->suspend_asm_sz);
return 0;
failed_map_iomuxc:
iounmap(suspend_info->m4if_base);
failed_map_m4if:
return ret;
}
static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
{
int ret;
struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
if (IS_ERR(gpc_dvfs_clk))
return PTR_ERR(gpc_dvfs_clk);
ret = clk_prepare_enable(gpc_dvfs_clk);
if (ret)
return ret;
arm_pm_idle = imx5_pm_idle;
ccm_base = ioremap(data->ccm_addr, SZ_16K);
cortex_base = ioremap(data->cortex_addr, SZ_16K);
gpc_base = ioremap(data->gpc_addr, SZ_16K);
WARN_ON(!ccm_base || !cortex_base || !gpc_base);
/* Set the registers to the default cpu idle state. */
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
ret = imx5_cpuidle_init();
if (ret)
pr_warn("%s: cpuidle init failed %d\n", __func__, ret);
ret = imx5_suspend_init(data);
if (ret)
pr_warn("%s: No DDR LPM support with suspend %d!\n",
__func__, ret);
suspend_set_ops(&mx5_suspend_ops);
return 0;
}
void __init imx51_pm_init(void)
{
if (IS_ENABLED(CONFIG_SOC_IMX51))
imx5_pm_common_init(&imx51_pm_data);
}
void __init imx53_pm_init(void)
{
if (IS_ENABLED(CONFIG_SOC_IMX53))
imx5_pm_common_init(&imx53_pm_data);
}