Skip to contentSkip to conversation

ARM: OMAP2+: AM33XX: Add suspend-resume support

PATCH Superseded Dave Gerlach 13 participants 106 messages Aug 6, 2013 – Sep 4, 2013

Subsystems (7)

v3 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

Changes in v3:
- Moved wkup_m3 code into separate driver
- Split up ti_emif header move
- Addressed clean-up comments
- Removed mailbox patches
- v2-v3 Discussion:
http://marc.info/?l=linux-arm-kernel&m=135698501821090&w=4

Changes in v2:
- Broke patches up to isolate assembly code and build hookup.
- Moved control module code to separate module
- v1->v2 Discussion:
http://lists.infradead.org/pipermail/linux-arm-kernel/2012-November/129508.html

Regards,
Dave

[1] http://marc.info/?l=linux-arm-kernel&m=137303736714638&w=4
[2] http://marc.info/?l=linux-omap&m=137303723114610&w=4
[3] http://marc.info/?l=linux-omap&m=137401384611934&w=4
[4] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=shortlog;h=refs/heads/next2

Dave Gerlach (1):
memory: emif: Move EMIF register defines to include/linux/

Vaibhav Bedia (8):
ARM: OMAP2+: AM33XX: control: Add some control module registers and
APIs
ARM: OMAP: DTB: Update IRQ data for WKUP_M3
ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec
ARM: OMAP2+: AM33XX: Add assembly code for PM operations
ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device
ARM: OMAP: omap_device: Add APIs to enable and idle hwmods
ARM: OMAP2+: AM33XX: Basic suspend resume support
ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP builds

 arch/arm/boot/dts/am33xx.dtsi       |    1 +
 arch/arm/mach-omap2/Kconfig         |    7 +-
 arch/arm/mach-omap2/Makefile        |    2 +
 arch/arm/mach-omap2/board-generic.c |    3 +-
 arch/arm/mach-omap2/common.c        |   28 ++
 arch/arm/mach-omap2/common.h        |   14 +
 arch/arm/mach-omap2/control.c       |   57 ++++
 arch/arm/mach-omap2/control.h       |   54 ++++
 arch/arm/mach-omap2/io.c            |    6 +
 arch/arm/mach-omap2/omap_device.c   |    8 +
 arch/arm/mach-omap2/omap_device.h   |    2 +
 arch/arm/mach-omap2/pm.c            |    3 +-
 arch/arm/mach-omap2/pm.h            |    5 +
 arch/arm/mach-omap2/pm33xx.c        |  474 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h        |   77 +++++
 arch/arm/mach-omap2/sleep33xx.S     |  350 ++++++++++++++++++++++
 arch/arm/mach-omap2/sram.c          |   10 +-
 arch/arm/mach-omap2/sram.h          |    2 +
 arch/arm/mach-omap2/timer.c         |   32 ++
 arch/arm/mach-omap2/wkup_m3.c       |  183 ++++++++++++
 drivers/memory/emif.h               |  543 +---------------------------------
 include/linux/ti_emif.h             |  558 +++++++++++++++++++++++++++++++++++
 22 files changed, 1872 insertions(+), 547 deletions(-)
 create mode 100644 arch/arm/mach-omap2/pm33xx.c
 create mode 100644 arch/arm/mach-omap2/pm33xx.h
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
 create mode 100644 arch/arm/mach-omap2/wkup_m3.c
 create mode 100644 include/linux/ti_emif.h
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH v3 1/9 memory: emif: Move EMIF register defines to include/linux/

OMAP4 and AM33XX share the same EMIF controller IP. Although there are significant differences in the IP integration due to which AM33XX can't reuse the EMIF driver DVFS similar to OMAP4, it can definitely benefit by reusing the EMIF related macros defined in drivers/memory/emif.h.

In the current OMAP PM framework the PM code resides under arch/arm/mach-omap2/. To enable reuse of the register defines move the register defines in the emif header file to include/linux so that both the EMIF driver and the AM33XX PM code can benefit.

Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Aneesh V <[email protected]>
---
 drivers/memory/emif.h   |  543 +--------------------------------------------
 include/linux/ti_emif.h |  558 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 559 insertions(+), 542 deletions(-)
 create mode 100644 include/linux/ti_emif.h
drivers/memory/emif.h +1 -542
index bfe08ba..8214f07 100644
@@ -12,548 +12,7 @@
 #ifndef __EMIF_H
 #define __EMIF_H
 
-/*
- * Maximum number of different frequencies supported by EMIF driver
- * Determines the number of entries in the pointer array for register
- * cache
- */
-#define EMIF_MAX_NUM_FREQUENCIES			6
-
-/* State of the core voltage */
-#define DDR_VOLTAGE_STABLE				0
-#define DDR_VOLTAGE_RAMPING				1
-
-/* Defines for timing De-rating */
-#define EMIF_NORMAL_TIMINGS				0
-#define EMIF_DERATED_TIMINGS				1
-
-/* Length of the forced read idle period in terms of cycles */
-#define EMIF_READ_IDLE_LEN_VAL				5
-
-/*
- * forced read idle interval to be used when voltage
- * is changed as part of DVFS/DPS - 1ms
- */
-#define READ_IDLE_INTERVAL_DVFS				(1*1000000)
-
-/*
- * Forced read idle interval to be used when voltage is stable
- * 50us - or maximum value will do
- */
-#define READ_IDLE_INTERVAL_NORMAL			(50*1000000)
-
-/* DLL calibration interval when voltage is NOT stable - 1us */
-#define DLL_CALIB_INTERVAL_DVFS				(1*1000000)
-
-#define DLL_CALIB_ACK_WAIT_VAL				5
-
-/* Interval between ZQCS commands - hw team recommended value */
-#define EMIF_ZQCS_INTERVAL_US				(50*1000)
-/* Enable ZQ Calibration on exiting Self-refresh */
-#define ZQ_SFEXITEN_ENABLE				1
-/*
- * ZQ Calibration simultaneously on both chip-selects:
- * Needs one calibration resistor per CS
- */
-#define	ZQ_DUALCALEN_DISABLE				0
-#define	ZQ_DUALCALEN_ENABLE				1
-
-#define T_ZQCS_DEFAULT_NS				90
-#define T_ZQCL_DEFAULT_NS				360
-#define T_ZQINIT_DEFAULT_NS				1000
-
-/* DPD_EN */
-#define DPD_DISABLE					0
-#define DPD_ENABLE					1
-
-/*
- * Default values for the low-power entry to be used if not provided by user.
- * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
- * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
- */
-#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE		2048
-#define EMIF_LP_MODE_TIMEOUT_POWER			512
-#define EMIF_LP_MODE_FREQ_THRESHOLD			400000000
-
-/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
-#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY		0x049FF000
-#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY	0x41
-#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY	0x80
-#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
-
-/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
-#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY		0x0E084200
-#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS	10000
-
-/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
-#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS		360
-
-#define EMIF_T_CSTA					3
-#define EMIF_T_PDLL_UL					128
-
-/* External PHY control registers magic values */
-#define EMIF_EXT_PHY_CTRL_1_VAL				0x04020080
-#define EMIF_EXT_PHY_CTRL_5_VAL				0x04010040
-#define EMIF_EXT_PHY_CTRL_6_VAL				0x01004010
-#define EMIF_EXT_PHY_CTRL_7_VAL				0x00001004
-#define EMIF_EXT_PHY_CTRL_8_VAL				0x04010040
-#define EMIF_EXT_PHY_CTRL_9_VAL				0x01004010
-#define EMIF_EXT_PHY_CTRL_10_VAL			0x00001004
-#define EMIF_EXT_PHY_CTRL_11_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_12_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_13_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_14_VAL			0x80080080
-#define EMIF_EXT_PHY_CTRL_15_VAL			0x00800800
-#define EMIF_EXT_PHY_CTRL_16_VAL			0x08102040
-#define EMIF_EXT_PHY_CTRL_17_VAL			0x00000001
-#define EMIF_EXT_PHY_CTRL_18_VAL			0x540A8150
-#define EMIF_EXT_PHY_CTRL_19_VAL			0xA81502A0
-#define EMIF_EXT_PHY_CTRL_20_VAL			0x002A0540
-#define EMIF_EXT_PHY_CTRL_21_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_22_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_23_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_24_VAL			0x00000077
-
-#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS	1200
-
-/* Registers offset */
-#define EMIF_MODULE_ID_AND_REVISION			0x0000
-#define EMIF_STATUS					0x0004
-#define EMIF_SDRAM_CONFIG				0x0008
-#define EMIF_SDRAM_CONFIG_2				0x000c
-#define EMIF_SDRAM_REFRESH_CONTROL			0x0010
-#define EMIF_SDRAM_REFRESH_CTRL_SHDW			0x0014
-#define EMIF_SDRAM_TIMING_1				0x0018
-#define EMIF_SDRAM_TIMING_1_SHDW			0x001c
-#define EMIF_SDRAM_TIMING_2				0x0020
-#define EMIF_SDRAM_TIMING_2_SHDW			0x0024
-#define EMIF_SDRAM_TIMING_3				0x0028
-#define EMIF_SDRAM_TIMING_3_SHDW			0x002c
-#define EMIF_LPDDR2_NVM_TIMING				0x0030
-#define EMIF_LPDDR2_NVM_TIMING_SHDW			0x0034
-#define EMIF_POWER_MANAGEMENT_CONTROL			0x0038
-#define EMIF_POWER_MANAGEMENT_CTRL_SHDW			0x003c
-#define EMIF_LPDDR2_MODE_REG_DATA			0x0040
-#define EMIF_LPDDR2_MODE_REG_CONFIG			0x0050
-#define EMIF_OCP_CONFIG					0x0054
-#define EMIF_OCP_CONFIG_VALUE_1				0x0058
-#define EMIF_OCP_CONFIG_VALUE_2				0x005c
-#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL		0x0060
-#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT		0x0064
-#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT	0x0068
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1	0x006c
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2	0x0070
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3	0x0074
-#define EMIF_PERFORMANCE_COUNTER_1			0x0080
-#define EMIF_PERFORMANCE_COUNTER_2			0x0084
-#define EMIF_PERFORMANCE_COUNTER_CONFIG			0x0088
-#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT	0x008c
-#define EMIF_PERFORMANCE_COUNTER_TIME			0x0090
-#define EMIF_MISC_REG					0x0094
-#define EMIF_DLL_CALIB_CTRL				0x0098
-#define EMIF_DLL_CALIB_CTRL_SHDW			0x009c
-#define EMIF_END_OF_INTERRUPT				0x00a0
-#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS		0x00a4
-#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS		0x00a8
-#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS		0x00ac
-#define EMIF_LL_OCP_INTERRUPT_STATUS			0x00b0
-#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET		0x00b4
-#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET		0x00b8
-#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR		0x00bc
-#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR		0x00c0
-#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG	0x00c8
-#define EMIF_TEMPERATURE_ALERT_CONFIG			0x00cc
-#define EMIF_OCP_ERROR_LOG				0x00d0
-#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW		0x00d4
-#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL		0x00d8
-#define EMIF_READ_WRITE_LEVELING_CONTROL		0x00dc
-#define EMIF_DDR_PHY_CTRL_1				0x00e4
-#define EMIF_DDR_PHY_CTRL_1_SHDW			0x00e8
-#define EMIF_DDR_PHY_CTRL_2				0x00ec
-#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING	0x0100
-#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
-#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
-#define EMIF_READ_WRITE_EXECUTION_THRESHOLD		0x0120
-#define EMIF_COS_CONFIG					0x0124
-#define EMIF_PHY_STATUS_1				0x0140
-#define EMIF_PHY_STATUS_2				0x0144
-#define EMIF_PHY_STATUS_3				0x0148
-#define EMIF_PHY_STATUS_4				0x014c
-#define EMIF_PHY_STATUS_5				0x0150
-#define EMIF_PHY_STATUS_6				0x0154
-#define EMIF_PHY_STATUS_7				0x0158
-#define EMIF_PHY_STATUS_8				0x015c
-#define EMIF_PHY_STATUS_9				0x0160
-#define EMIF_PHY_STATUS_10				0x0164
-#define EMIF_PHY_STATUS_11				0x0168
-#define EMIF_PHY_STATUS_12				0x016c
-#define EMIF_PHY_STATUS_13				0x0170
-#define EMIF_PHY_STATUS_14				0x0174
-#define EMIF_PHY_STATUS_15				0x0178
-#define EMIF_PHY_STATUS_16				0x017c
-#define EMIF_PHY_STATUS_17				0x0180
-#define EMIF_PHY_STATUS_18				0x0184
-#define EMIF_PHY_STATUS_19				0x0188
-#define EMIF_PHY_STATUS_20				0x018c
-#define EMIF_PHY_STATUS_21				0x0190
-#define EMIF_EXT_PHY_CTRL_1				0x0200
-#define EMIF_EXT_PHY_CTRL_1_SHDW			0x0204
-#define EMIF_EXT_PHY_CTRL_2				0x0208
-#define EMIF_EXT_PHY_CTRL_2_SHDW			0x020c
-#define EMIF_EXT_PHY_CTRL_3				0x0210
-#define EMIF_EXT_PHY_CTRL_3_SHDW			0x0214
-#define EMIF_EXT_PHY_CTRL_4				0x0218
-#define EMIF_EXT_PHY_CTRL_4_SHDW			0x021c
-#define EMIF_EXT_PHY_CTRL_5				0x0220
-#define EMIF_EXT_PHY_CTRL_5_SHDW			0x0224
-#define EMIF_EXT_PHY_CTRL_6				0x0228
-#define EMIF_EXT_PHY_CTRL_6_SHDW			0x022c
-#define EMIF_EXT_PHY_CTRL_7				0x0230
-#define EMIF_EXT_PHY_CTRL_7_SHDW			0x0234
-#define EMIF_EXT_PHY_CTRL_8				0x0238
-#define EMIF_EXT_PHY_CTRL_8_SHDW			0x023c
-#define EMIF_EXT_PHY_CTRL_9				0x0240
-#define EMIF_EXT_PHY_CTRL_9_SHDW			0x0244
-#define EMIF_EXT_PHY_CTRL_10				0x0248
-#define EMIF_EXT_PHY_CTRL_10_SHDW			0x024c
-#define EMIF_EXT_PHY_CTRL_11				0x0250
-#define EMIF_EXT_PHY_CTRL_11_SHDW			0x0254
-#define EMIF_EXT_PHY_CTRL_12				0x0258
-#define EMIF_EXT_PHY_CTRL_12_SHDW			0x025c
-#define EMIF_EXT_PHY_CTRL_13				0x0260
-#define EMIF_EXT_PHY_CTRL_13_SHDW			0x0264
-#define EMIF_EXT_PHY_CTRL_14				0x0268
-#define EMIF_EXT_PHY_CTRL_14_SHDW			0x026c
-#define EMIF_EXT_PHY_CTRL_15				0x0270
-#define EMIF_EXT_PHY_CTRL_15_SHDW			0x0274
-#define EMIF_EXT_PHY_CTRL_16				0x0278
-#define EMIF_EXT_PHY_CTRL_16_SHDW			0x027c
-#define EMIF_EXT_PHY_CTRL_17				0x0280
-#define EMIF_EXT_PHY_CTRL_17_SHDW			0x0284
-#define EMIF_EXT_PHY_CTRL_18				0x0288
-#define EMIF_EXT_PHY_CTRL_18_SHDW			0x028c
-#define EMIF_EXT_PHY_CTRL_19				0x0290
-#define EMIF_EXT_PHY_CTRL_19_SHDW			0x0294
-#define EMIF_EXT_PHY_CTRL_20				0x0298
-#define EMIF_EXT_PHY_CTRL_20_SHDW			0x029c
-#define EMIF_EXT_PHY_CTRL_21				0x02a0
-#define EMIF_EXT_PHY_CTRL_21_SHDW			0x02a4
-#define EMIF_EXT_PHY_CTRL_22				0x02a8
-#define EMIF_EXT_PHY_CTRL_22_SHDW			0x02ac
-#define EMIF_EXT_PHY_CTRL_23				0x02b0
-#define EMIF_EXT_PHY_CTRL_23_SHDW			0x02b4
-#define EMIF_EXT_PHY_CTRL_24				0x02b8
-#define EMIF_EXT_PHY_CTRL_24_SHDW			0x02bc
-#define EMIF_EXT_PHY_CTRL_25				0x02c0
-#define EMIF_EXT_PHY_CTRL_25_SHDW			0x02c4
-#define EMIF_EXT_PHY_CTRL_26				0x02c8
-#define EMIF_EXT_PHY_CTRL_26_SHDW			0x02cc
-#define EMIF_EXT_PHY_CTRL_27				0x02d0
-#define EMIF_EXT_PHY_CTRL_27_SHDW			0x02d4
-#define EMIF_EXT_PHY_CTRL_28				0x02d8
-#define EMIF_EXT_PHY_CTRL_28_SHDW			0x02dc
-#define EMIF_EXT_PHY_CTRL_29				0x02e0
-#define EMIF_EXT_PHY_CTRL_29_SHDW			0x02e4
-#define EMIF_EXT_PHY_CTRL_30				0x02e8
-#define EMIF_EXT_PHY_CTRL_30_SHDW			0x02ec
-
-/* Registers shifts and masks */
-
-/* EMIF_MODULE_ID_AND_REVISION */
-#define SCHEME_SHIFT					30
-#define SCHEME_MASK					(0x3 << 30)
-#define MODULE_ID_SHIFT					16
-#define MODULE_ID_MASK					(0xfff << 16)
-#define RTL_VERSION_SHIFT				11
-#define RTL_VERSION_MASK				(0x1f << 11)
-#define MAJOR_REVISION_SHIFT				8
-#define MAJOR_REVISION_MASK				(0x7 << 8)
-#define MINOR_REVISION_SHIFT				0
-#define MINOR_REVISION_MASK				(0x3f << 0)
-
-/* STATUS */
-#define BE_SHIFT					31
-#define BE_MASK						(1 << 31)
-#define DUAL_CLK_MODE_SHIFT				30
-#define DUAL_CLK_MODE_MASK				(1 << 30)
-#define FAST_INIT_SHIFT					29
-#define FAST_INIT_MASK					(1 << 29)
-#define RDLVLGATETO_SHIFT				6
-#define RDLVLGATETO_MASK				(1 << 6)
-#define RDLVLTO_SHIFT					5
-#define RDLVLTO_MASK					(1 << 5)
-#define WRLVLTO_SHIFT					4
-#define WRLVLTO_MASK					(1 << 4)
-#define PHY_DLL_READY_SHIFT				2
-#define PHY_DLL_READY_MASK				(1 << 2)
-
-/* SDRAM_CONFIG */
-#define SDRAM_TYPE_SHIFT				29
-#define SDRAM_TYPE_MASK					(0x7 << 29)
-#define IBANK_POS_SHIFT					27
-#define IBANK_POS_MASK					(0x3 << 27)
-#define DDR_TERM_SHIFT					24
-#define DDR_TERM_MASK					(0x7 << 24)
-#define DDR2_DDQS_SHIFT					23
-#define DDR2_DDQS_MASK					(1 << 23)
-#define DYN_ODT_SHIFT					21
-#define DYN_ODT_MASK					(0x3 << 21)
-#define DDR_DISABLE_DLL_SHIFT				20
-#define DDR_DISABLE_DLL_MASK				(1 << 20)
-#define SDRAM_DRIVE_SHIFT				18
-#define SDRAM_DRIVE_MASK				(0x3 << 18)
-#define CWL_SHIFT					16
-#define CWL_MASK					(0x3 << 16)
-#define NARROW_MODE_SHIFT				14
-#define NARROW_MODE_MASK				(0x3 << 14)
-#define CL_SHIFT					10
-#define CL_MASK						(0xf << 10)
-#define ROWSIZE_SHIFT					7
-#define ROWSIZE_MASK					(0x7 << 7)
-#define IBANK_SHIFT					4
-#define IBANK_MASK					(0x7 << 4)
-#define EBANK_SHIFT					3
-#define EBANK_MASK					(1 << 3)
-#define PAGESIZE_SHIFT					0
-#define PAGESIZE_MASK					(0x7 << 0)
-
-/* SDRAM_CONFIG_2 */
-#define CS1NVMEN_SHIFT					30
-#define CS1NVMEN_MASK					(1 << 30)
-#define EBANK_POS_SHIFT					27
-#define EBANK_POS_MASK					(1 << 27)
-#define RDBNUM_SHIFT					4
-#define RDBNUM_MASK					(0x3 << 4)
-#define RDBSIZE_SHIFT					0
-#define RDBSIZE_MASK					(0x7 << 0)
-
-/* SDRAM_REFRESH_CONTROL */
-#define INITREF_DIS_SHIFT				31
-#define INITREF_DIS_MASK				(1 << 31)
-#define SRT_SHIFT					29
-#define SRT_MASK					(1 << 29)
-#define ASR_SHIFT					28
-#define ASR_MASK					(1 << 28)
-#define PASR_SHIFT					24
-#define PASR_MASK					(0x7 << 24)
-#define REFRESH_RATE_SHIFT				0
-#define REFRESH_RATE_MASK				(0xffff << 0)
-
-/* SDRAM_TIMING_1 */
-#define T_RTW_SHIFT					29
-#define T_RTW_MASK					(0x7 << 29)
-#define T_RP_SHIFT					25
-#define T_RP_MASK					(0xf << 25)
-#define T_RCD_SHIFT					21
-#define T_RCD_MASK					(0xf << 21)
-#define T_WR_SHIFT					17
-#define T_WR_MASK					(0xf << 17)
-#define T_RAS_SHIFT					12
-#define T_RAS_MASK					(0x1f << 12)
-#define T_RC_SHIFT					6
-#define T_RC_MASK					(0x3f << 6)
-#define T_RRD_SHIFT					3
-#define T_RRD_MASK					(0x7 << 3)
-#define T_WTR_SHIFT					0
-#define T_WTR_MASK					(0x7 << 0)
-
-/* SDRAM_TIMING_2 */
-#define T_XP_SHIFT					28
-#define T_XP_MASK					(0x7 << 28)
-#define T_ODT_SHIFT					25
-#define T_ODT_MASK					(0x7 << 25)
-#define T_XSNR_SHIFT					16
-#define T_XSNR_MASK					(0x1ff << 16)
-#define T_XSRD_SHIFT					6
-#define T_XSRD_MASK					(0x3ff << 6)
-#define T_RTP_SHIFT					3
-#define T_RTP_MASK					(0x7 << 3)
-#define T_CKE_SHIFT					0
-#define T_CKE_MASK					(0x7 << 0)
-
-/* SDRAM_TIMING_3 */
-#define T_PDLL_UL_SHIFT					28
-#define T_PDLL_UL_MASK					(0xf << 28)
-#define T_CSTA_SHIFT					24
-#define T_CSTA_MASK					(0xf << 24)
-#define T_CKESR_SHIFT					21
-#define T_CKESR_MASK					(0x7 << 21)
-#define ZQ_ZQCS_SHIFT					15
-#define ZQ_ZQCS_MASK					(0x3f << 15)
-#define T_TDQSCKMAX_SHIFT				13
-#define T_TDQSCKMAX_MASK				(0x3 << 13)
-#define T_RFC_SHIFT					4
-#define T_RFC_MASK					(0x1ff << 4)
-#define T_RAS_MAX_SHIFT					0
-#define T_RAS_MAX_MASK					(0xf << 0)
-
-/* POWER_MANAGEMENT_CONTROL */
-#define PD_TIM_SHIFT					12
-#define PD_TIM_MASK					(0xf << 12)
-#define DPD_EN_SHIFT					11
-#define DPD_EN_MASK					(1 << 11)
-#define LP_MODE_SHIFT					8
-#define LP_MODE_MASK					(0x7 << 8)
-#define SR_TIM_SHIFT					4
-#define SR_TIM_MASK					(0xf << 4)
-#define CS_TIM_SHIFT					0
-#define CS_TIM_MASK					(0xf << 0)
-
-/* LPDDR2_MODE_REG_DATA */
-#define VALUE_0_SHIFT					0
-#define VALUE_0_MASK					(0x7f << 0)
-
-/* LPDDR2_MODE_REG_CONFIG */
-#define CS_SHIFT					31
-#define CS_MASK						(1 << 31)
-#define REFRESH_EN_SHIFT				30
-#define REFRESH_EN_MASK					(1 << 30)
-#define ADDRESS_SHIFT					0
-#define ADDRESS_MASK					(0xff << 0)
-
-/* OCP_CONFIG */
-#define SYS_THRESH_MAX_SHIFT				24
-#define SYS_THRESH_MAX_MASK				(0xf << 24)
-#define MPU_THRESH_MAX_SHIFT				20
-#define MPU_THRESH_MAX_MASK				(0xf << 20)
-#define LL_THRESH_MAX_SHIFT				16
-#define LL_THRESH_MAX_MASK				(0xf << 16)
-
-/* PERFORMANCE_COUNTER_1 */
-#define COUNTER1_SHIFT					0
-#define COUNTER1_MASK					(0xffffffff << 0)
-
-/* PERFORMANCE_COUNTER_2 */
-#define COUNTER2_SHIFT					0
-#define COUNTER2_MASK					(0xffffffff << 0)
-
-/* PERFORMANCE_COUNTER_CONFIG */
-#define CNTR2_MCONNID_EN_SHIFT				31
-#define CNTR2_MCONNID_EN_MASK				(1 << 31)
-#define CNTR2_REGION_EN_SHIFT				30
-#define CNTR2_REGION_EN_MASK				(1 << 30)
-#define CNTR2_CFG_SHIFT					16
-#define CNTR2_CFG_MASK					(0xf << 16)
-#define CNTR1_MCONNID_EN_SHIFT				15
-#define CNTR1_MCONNID_EN_MASK				(1 << 15)
-#define CNTR1_REGION_EN_SHIFT				14
-#define CNTR1_REGION_EN_MASK				(1 << 14)
-#define CNTR1_CFG_SHIFT					0
-#define CNTR1_CFG_MASK					(0xf << 0)
-
-/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
-#define MCONNID2_SHIFT					24
-#define MCONNID2_MASK					(0xff << 24)
-#define REGION_SEL2_SHIFT				16
-#define REGION_SEL2_MASK				(0x3 << 16)
-#define MCONNID1_SHIFT					8
-#define MCONNID1_MASK					(0xff << 8)
-#define REGION_SEL1_SHIFT				0
-#define REGION_SEL1_MASK				(0x3 << 0)
-
-/* PERFORMANCE_COUNTER_TIME */
-#define TOTAL_TIME_SHIFT				0
-#define TOTAL_TIME_MASK					(0xffffffff << 0)
-
-/* DLL_CALIB_CTRL */
-#define ACK_WAIT_SHIFT					16
-#define ACK_WAIT_MASK					(0xf << 16)
-#define DLL_CALIB_INTERVAL_SHIFT			0
-#define DLL_CALIB_INTERVAL_MASK				(0x1ff << 0)
-
-/* END_OF_INTERRUPT */
-#define EOI_SHIFT					0
-#define EOI_MASK					(1 << 0)
-
-/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
-#define DNV_SYS_SHIFT					2
-#define DNV_SYS_MASK					(1 << 2)
-#define TA_SYS_SHIFT					1
-#define TA_SYS_MASK					(1 << 1)
-#define ERR_SYS_SHIFT					0
-#define ERR_SYS_MASK					(1 << 0)
-
-/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
-#define DNV_LL_SHIFT					2
-#define DNV_LL_MASK					(1 << 2)
-#define TA_LL_SHIFT					1
-#define TA_LL_MASK					(1 << 1)
-#define ERR_LL_SHIFT					0
-#define ERR_LL_MASK					(1 << 0)
-
-/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
-#define EN_DNV_SYS_SHIFT				2
-#define EN_DNV_SYS_MASK					(1 << 2)
-#define EN_TA_SYS_SHIFT					1
-#define EN_TA_SYS_MASK					(1 << 1)
-#define EN_ERR_SYS_SHIFT					0
-#define EN_ERR_SYS_MASK					(1 << 0)
-
-/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
-#define EN_DNV_LL_SHIFT					2
-#define EN_DNV_LL_MASK					(1 << 2)
-#define EN_TA_LL_SHIFT					1
-#define EN_TA_LL_MASK					(1 << 1)
-#define EN_ERR_LL_SHIFT					0
-#define EN_ERR_LL_MASK					(1 << 0)
-
-/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
-#define ZQ_CS1EN_SHIFT					31
-#define ZQ_CS1EN_MASK					(1 << 31)
-#define ZQ_CS0EN_SHIFT					30
-#define ZQ_CS0EN_MASK					(1 << 30)
-#define ZQ_DUALCALEN_SHIFT				29
-#define ZQ_DUALCALEN_MASK				(1 << 29)
-#define ZQ_SFEXITEN_SHIFT				28
-#define ZQ_SFEXITEN_MASK				(1 << 28)
-#define ZQ_ZQINIT_MULT_SHIFT				18
-#define ZQ_ZQINIT_MULT_MASK				(0x3 << 18)
-#define ZQ_ZQCL_MULT_SHIFT				16
-#define ZQ_ZQCL_MULT_MASK				(0x3 << 16)
-#define ZQ_REFINTERVAL_SHIFT				0
-#define ZQ_REFINTERVAL_MASK				(0xffff << 0)
-
-/* TEMPERATURE_ALERT_CONFIG */
-#define TA_CS1EN_SHIFT					31
-#define TA_CS1EN_MASK					(1 << 31)
-#define TA_CS0EN_SHIFT					30
-#define TA_CS0EN_MASK					(1 << 30)
-#define TA_SFEXITEN_SHIFT				28
-#define TA_SFEXITEN_MASK				(1 << 28)
-#define TA_DEVWDT_SHIFT					26
-#define TA_DEVWDT_MASK					(0x3 << 26)
-#define TA_DEVCNT_SHIFT					24
-#define TA_DEVCNT_MASK					(0x3 << 24)
-#define TA_REFINTERVAL_SHIFT				0
-#define TA_REFINTERVAL_MASK				(0x3fffff << 0)
-
-/* OCP_ERROR_LOG */
-#define MADDRSPACE_SHIFT				14
-#define MADDRSPACE_MASK					(0x3 << 14)
-#define MBURSTSEQ_SHIFT					11
-#define MBURSTSEQ_MASK					(0x7 << 11)
-#define MCMD_SHIFT					8
-#define MCMD_MASK					(0x7 << 8)
-#define MCONNID_SHIFT					0
-#define MCONNID_MASK					(0xff << 0)
-
-/* DDR_PHY_CTRL_1 - EMIF4D */
-#define DLL_SLAVE_DLY_CTRL_SHIFT_4D			4
-#define DLL_SLAVE_DLY_CTRL_MASK_4D			(0xFF << 4)
-#define READ_LATENCY_SHIFT_4D				0
-#define READ_LATENCY_MASK_4D				(0xf << 0)
-
-/* DDR_PHY_CTRL_1 - EMIF4D5 */
-#define DLL_HALF_DELAY_SHIFT_4D5			21
-#define DLL_HALF_DELAY_MASK_4D5				(1 << 21)
-#define READ_LATENCY_SHIFT_4D5				0
-#define READ_LATENCY_MASK_4D5				(0x1f << 0)
-
-/* DDR_PHY_CTRL_1_SHDW */
-#define DDR_PHY_CTRL_1_SHDW_SHIFT			5
-#define DDR_PHY_CTRL_1_SHDW_MASK			(0x7ffffff << 5)
-#define READ_LATENCY_SHDW_SHIFT				0
-#define READ_LATENCY_SHDW_MASK				(0x1f << 0)
+#include <linux/ti_emif.h>
 
 #ifndef __ASSEMBLY__
 /*
include/linux/ti_emif.h new file +558 -0

558 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#2 lore raw

PATCH v3 1/9 memory: emif: Move EMIF register defines to include/linux/

Quoted 11 lines · Dave Gerlach

OMAP4 and AM33XX share the same EMIF controller IP. Although there are significant differences in the IP integration due to which AM33XX can't reuse the EMIF driver DVFS similar to OMAP4, it can definitely benefit by reusing the EMIF related macros defined in drivers/memory/emif.h.

In the current OMAP PM framework the PM code resides under arch/arm/mach-omap2/. To enable reuse of the register defines move the register defines in the emif header file to include/linux so that both the EMIF driver and the AM33XX PM code can benefit.

Quoted 4 lines
Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Aneesh V <[email protected]>
Quoted 1,131 lines
---
 drivers/memory/emif.h   |  543 +--------------------------------------------
 include/linux/ti_emif.h |  558 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 559 insertions(+), 542 deletions(-)
 create mode 100644 include/linux/ti_emif.h
drivers/memory/emif.h +1 -542
index bfe08ba..8214f07 100644
@@ -12,548 +12,7 @@
 #ifndef __EMIF_H
 #define __EMIF_H
 
-/*
- * Maximum number of different frequencies supported by EMIF driver
- * Determines the number of entries in the pointer array for register
- * cache
- */
-#define EMIF_MAX_NUM_FREQUENCIES                       6
-
-/* State of the core voltage */
-#define DDR_VOLTAGE_STABLE                             0
-#define DDR_VOLTAGE_RAMPING                            1
-
-/* Defines for timing De-rating */
-#define EMIF_NORMAL_TIMINGS                            0
-#define EMIF_DERATED_TIMINGS                           1
-
-/* Length of the forced read idle period in terms of cycles */
-#define EMIF_READ_IDLE_LEN_VAL                         5
-
-/*
- * forced read idle interval to be used when voltage
- * is changed as part of DVFS/DPS - 1ms
- */
-#define READ_IDLE_INTERVAL_DVFS                                (1*1000000)
-
-/*
- * Forced read idle interval to be used when voltage is stable
- * 50us - or maximum value will do
- */
-#define READ_IDLE_INTERVAL_NORMAL                      (50*1000000)
-
-/* DLL calibration interval when voltage is NOT stable - 1us */
-#define DLL_CALIB_INTERVAL_DVFS                                (1*1000000)
-
-#define DLL_CALIB_ACK_WAIT_VAL                         5
-
-/* Interval between ZQCS commands - hw team recommended value */
-#define EMIF_ZQCS_INTERVAL_US                          (50*1000)
-/* Enable ZQ Calibration on exiting Self-refresh */
-#define ZQ_SFEXITEN_ENABLE                             1
-/*
- * ZQ Calibration simultaneously on both chip-selects:
- * Needs one calibration resistor per CS
- */
-#define        ZQ_DUALCALEN_DISABLE                            0
-#define        ZQ_DUALCALEN_ENABLE                             1
-
-#define T_ZQCS_DEFAULT_NS                              90
-#define T_ZQCL_DEFAULT_NS                              360
-#define T_ZQINIT_DEFAULT_NS                            1000
-
-/* DPD_EN */
-#define DPD_DISABLE                                    0
-#define DPD_ENABLE                                     1
-
-/*
- * Default values for the low-power entry to be used if not provided by user.
- * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
- * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
- */
-#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE               2048
-#define EMIF_LP_MODE_TIMEOUT_POWER                     512
-#define EMIF_LP_MODE_FREQ_THRESHOLD                    400000000
-
-/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
-#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY         0x049FF000
-#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY      0x41
-#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY      0x80
-#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
-
-/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
-#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY                0x0E084200
-#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS      10000
-
-/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
-#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS            360
-
-#define EMIF_T_CSTA                                    3
-#define EMIF_T_PDLL_UL                                 128
-
-/* External PHY control registers magic values */
-#define EMIF_EXT_PHY_CTRL_1_VAL                                0x04020080
-#define EMIF_EXT_PHY_CTRL_5_VAL                                0x04010040
-#define EMIF_EXT_PHY_CTRL_6_VAL                                0x01004010
-#define EMIF_EXT_PHY_CTRL_7_VAL                                0x00001004
-#define EMIF_EXT_PHY_CTRL_8_VAL                                0x04010040
-#define EMIF_EXT_PHY_CTRL_9_VAL                                0x01004010
-#define EMIF_EXT_PHY_CTRL_10_VAL                       0x00001004
-#define EMIF_EXT_PHY_CTRL_11_VAL                       0x00000000
-#define EMIF_EXT_PHY_CTRL_12_VAL                       0x00000000
-#define EMIF_EXT_PHY_CTRL_13_VAL                       0x00000000
-#define EMIF_EXT_PHY_CTRL_14_VAL                       0x80080080
-#define EMIF_EXT_PHY_CTRL_15_VAL                       0x00800800
-#define EMIF_EXT_PHY_CTRL_16_VAL                       0x08102040
-#define EMIF_EXT_PHY_CTRL_17_VAL                       0x00000001
-#define EMIF_EXT_PHY_CTRL_18_VAL                       0x540A8150
-#define EMIF_EXT_PHY_CTRL_19_VAL                       0xA81502A0
-#define EMIF_EXT_PHY_CTRL_20_VAL                       0x002A0540
-#define EMIF_EXT_PHY_CTRL_21_VAL                       0x00000000
-#define EMIF_EXT_PHY_CTRL_22_VAL                       0x00000000
-#define EMIF_EXT_PHY_CTRL_23_VAL                       0x00000000
-#define EMIF_EXT_PHY_CTRL_24_VAL                       0x00000077
-
-#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS     1200
-
-/* Registers offset */
-#define EMIF_MODULE_ID_AND_REVISION                    0x0000
-#define EMIF_STATUS                                    0x0004
-#define EMIF_SDRAM_CONFIG                              0x0008
-#define EMIF_SDRAM_CONFIG_2                            0x000c
-#define EMIF_SDRAM_REFRESH_CONTROL                     0x0010
-#define EMIF_SDRAM_REFRESH_CTRL_SHDW                   0x0014
-#define EMIF_SDRAM_TIMING_1                            0x0018
-#define EMIF_SDRAM_TIMING_1_SHDW                       0x001c
-#define EMIF_SDRAM_TIMING_2                            0x0020
-#define EMIF_SDRAM_TIMING_2_SHDW                       0x0024
-#define EMIF_SDRAM_TIMING_3                            0x0028
-#define EMIF_SDRAM_TIMING_3_SHDW                       0x002c
-#define EMIF_LPDDR2_NVM_TIMING                         0x0030
-#define EMIF_LPDDR2_NVM_TIMING_SHDW                    0x0034
-#define EMIF_POWER_MANAGEMENT_CONTROL                  0x0038
-#define EMIF_POWER_MANAGEMENT_CTRL_SHDW                        0x003c
-#define EMIF_LPDDR2_MODE_REG_DATA                      0x0040
-#define EMIF_LPDDR2_MODE_REG_CONFIG                    0x0050
-#define EMIF_OCP_CONFIG                                        0x0054
-#define EMIF_OCP_CONFIG_VALUE_1                                0x0058
-#define EMIF_OCP_CONFIG_VALUE_2                                0x005c
-#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL           0x0060
-#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT         0x0064
-#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT      0x0068
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1       0x006c
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2       0x0070
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3       0x0074
-#define EMIF_PERFORMANCE_COUNTER_1                     0x0080
-#define EMIF_PERFORMANCE_COUNTER_2                     0x0084
-#define EMIF_PERFORMANCE_COUNTER_CONFIG                        0x0088
-#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT  0x008c
-#define EMIF_PERFORMANCE_COUNTER_TIME                  0x0090
-#define EMIF_MISC_REG                                  0x0094
-#define EMIF_DLL_CALIB_CTRL                            0x0098
-#define EMIF_DLL_CALIB_CTRL_SHDW                       0x009c
-#define EMIF_END_OF_INTERRUPT                          0x00a0
-#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS           0x00a4
-#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS               0x00a8
-#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS               0x00ac
-#define EMIF_LL_OCP_INTERRUPT_STATUS                   0x00b0
-#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET           0x00b4
-#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET               0x00b8
-#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR         0x00bc
-#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR             0x00c0
-#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG 0x00c8
-#define EMIF_TEMPERATURE_ALERT_CONFIG                  0x00cc
-#define EMIF_OCP_ERROR_LOG                             0x00d0
-#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW           0x00d4
-#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL          0x00d8
-#define EMIF_READ_WRITE_LEVELING_CONTROL               0x00dc
-#define EMIF_DDR_PHY_CTRL_1                            0x00e4
-#define EMIF_DDR_PHY_CTRL_1_SHDW                       0x00e8
-#define EMIF_DDR_PHY_CTRL_2                            0x00ec
-#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING      0x0100
-#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
-#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
-#define EMIF_READ_WRITE_EXECUTION_THRESHOLD            0x0120
-#define EMIF_COS_CONFIG                                        0x0124
-#define EMIF_PHY_STATUS_1                              0x0140
-#define EMIF_PHY_STATUS_2                              0x0144
-#define EMIF_PHY_STATUS_3                              0x0148
-#define EMIF_PHY_STATUS_4                              0x014c
-#define EMIF_PHY_STATUS_5                              0x0150
-#define EMIF_PHY_STATUS_6                              0x0154
-#define EMIF_PHY_STATUS_7                              0x0158
-#define EMIF_PHY_STATUS_8                              0x015c
-#define EMIF_PHY_STATUS_9                              0x0160
-#define EMIF_PHY_STATUS_10                             0x0164
-#define EMIF_PHY_STATUS_11                             0x0168
-#define EMIF_PHY_STATUS_12                             0x016c
-#define EMIF_PHY_STATUS_13                             0x0170
-#define EMIF_PHY_STATUS_14                             0x0174
-#define EMIF_PHY_STATUS_15                             0x0178
-#define EMIF_PHY_STATUS_16                             0x017c
-#define EMIF_PHY_STATUS_17                             0x0180
-#define EMIF_PHY_STATUS_18                             0x0184
-#define EMIF_PHY_STATUS_19                             0x0188
-#define EMIF_PHY_STATUS_20                             0x018c
-#define EMIF_PHY_STATUS_21                             0x0190
-#define EMIF_EXT_PHY_CTRL_1                            0x0200
-#define EMIF_EXT_PHY_CTRL_1_SHDW                       0x0204
-#define EMIF_EXT_PHY_CTRL_2                            0x0208
-#define EMIF_EXT_PHY_CTRL_2_SHDW                       0x020c
-#define EMIF_EXT_PHY_CTRL_3                            0x0210
-#define EMIF_EXT_PHY_CTRL_3_SHDW                       0x0214
-#define EMIF_EXT_PHY_CTRL_4                            0x0218
-#define EMIF_EXT_PHY_CTRL_4_SHDW                       0x021c
-#define EMIF_EXT_PHY_CTRL_5                            0x0220
-#define EMIF_EXT_PHY_CTRL_5_SHDW                       0x0224
-#define EMIF_EXT_PHY_CTRL_6                            0x0228
-#define EMIF_EXT_PHY_CTRL_6_SHDW                       0x022c
-#define EMIF_EXT_PHY_CTRL_7                            0x0230
-#define EMIF_EXT_PHY_CTRL_7_SHDW                       0x0234
-#define EMIF_EXT_PHY_CTRL_8                            0x0238
-#define EMIF_EXT_PHY_CTRL_8_SHDW                       0x023c
-#define EMIF_EXT_PHY_CTRL_9                            0x0240
-#define EMIF_EXT_PHY_CTRL_9_SHDW                       0x0244
-#define EMIF_EXT_PHY_CTRL_10                           0x0248
-#define EMIF_EXT_PHY_CTRL_10_SHDW                      0x024c
-#define EMIF_EXT_PHY_CTRL_11                           0x0250
-#define EMIF_EXT_PHY_CTRL_11_SHDW                      0x0254
-#define EMIF_EXT_PHY_CTRL_12                           0x0258
-#define EMIF_EXT_PHY_CTRL_12_SHDW                      0x025c
-#define EMIF_EXT_PHY_CTRL_13                           0x0260
-#define EMIF_EXT_PHY_CTRL_13_SHDW                      0x0264
-#define EMIF_EXT_PHY_CTRL_14                           0x0268
-#define EMIF_EXT_PHY_CTRL_14_SHDW                      0x026c
-#define EMIF_EXT_PHY_CTRL_15                           0x0270
-#define EMIF_EXT_PHY_CTRL_15_SHDW                      0x0274
-#define EMIF_EXT_PHY_CTRL_16                           0x0278
-#define EMIF_EXT_PHY_CTRL_16_SHDW                      0x027c
-#define EMIF_EXT_PHY_CTRL_17                           0x0280
-#define EMIF_EXT_PHY_CTRL_17_SHDW                      0x0284
-#define EMIF_EXT_PHY_CTRL_18                           0x0288
-#define EMIF_EXT_PHY_CTRL_18_SHDW                      0x028c
-#define EMIF_EXT_PHY_CTRL_19                           0x0290
-#define EMIF_EXT_PHY_CTRL_19_SHDW                      0x0294
-#define EMIF_EXT_PHY_CTRL_20                           0x0298
-#define EMIF_EXT_PHY_CTRL_20_SHDW                      0x029c
-#define EMIF_EXT_PHY_CTRL_21                           0x02a0
-#define EMIF_EXT_PHY_CTRL_21_SHDW                      0x02a4
-#define EMIF_EXT_PHY_CTRL_22                           0x02a8
-#define EMIF_EXT_PHY_CTRL_22_SHDW                      0x02ac
-#define EMIF_EXT_PHY_CTRL_23                           0x02b0
-#define EMIF_EXT_PHY_CTRL_23_SHDW                      0x02b4
-#define EMIF_EXT_PHY_CTRL_24                           0x02b8
-#define EMIF_EXT_PHY_CTRL_24_SHDW                      0x02bc
-#define EMIF_EXT_PHY_CTRL_25                           0x02c0
-#define EMIF_EXT_PHY_CTRL_25_SHDW                      0x02c4
-#define EMIF_EXT_PHY_CTRL_26                           0x02c8
-#define EMIF_EXT_PHY_CTRL_26_SHDW                      0x02cc
-#define EMIF_EXT_PHY_CTRL_27                           0x02d0
-#define EMIF_EXT_PHY_CTRL_27_SHDW                      0x02d4
-#define EMIF_EXT_PHY_CTRL_28                           0x02d8
-#define EMIF_EXT_PHY_CTRL_28_SHDW                      0x02dc
-#define EMIF_EXT_PHY_CTRL_29                           0x02e0
-#define EMIF_EXT_PHY_CTRL_29_SHDW                      0x02e4
-#define EMIF_EXT_PHY_CTRL_30                           0x02e8
-#define EMIF_EXT_PHY_CTRL_30_SHDW                      0x02ec
-
-/* Registers shifts and masks */
-
-/* EMIF_MODULE_ID_AND_REVISION */
-#define SCHEME_SHIFT                                   30
-#define SCHEME_MASK                                    (0x3 << 30)
-#define MODULE_ID_SHIFT                                        16
-#define MODULE_ID_MASK                                 (0xfff << 16)
-#define RTL_VERSION_SHIFT                              11
-#define RTL_VERSION_MASK                               (0x1f << 11)
-#define MAJOR_REVISION_SHIFT                           8
-#define MAJOR_REVISION_MASK                            (0x7 << 8)
-#define MINOR_REVISION_SHIFT                           0
-#define MINOR_REVISION_MASK                            (0x3f << 0)
-
-/* STATUS */
-#define BE_SHIFT                                       31
-#define BE_MASK                                                (1 << 31)
-#define DUAL_CLK_MODE_SHIFT                            30
-#define DUAL_CLK_MODE_MASK                             (1 << 30)
-#define FAST_INIT_SHIFT                                        29
-#define FAST_INIT_MASK                                 (1 << 29)
-#define RDLVLGATETO_SHIFT                              6
-#define RDLVLGATETO_MASK                               (1 << 6)
-#define RDLVLTO_SHIFT                                  5
-#define RDLVLTO_MASK                                   (1 << 5)
-#define WRLVLTO_SHIFT                                  4
-#define WRLVLTO_MASK                                   (1 << 4)
-#define PHY_DLL_READY_SHIFT                            2
-#define PHY_DLL_READY_MASK                             (1 << 2)
-
-/* SDRAM_CONFIG */
-#define SDRAM_TYPE_SHIFT                               29
-#define SDRAM_TYPE_MASK                                        (0x7 << 29)
-#define IBANK_POS_SHIFT                                        27
-#define IBANK_POS_MASK                                 (0x3 << 27)
-#define DDR_TERM_SHIFT                                 24
-#define DDR_TERM_MASK                                  (0x7 << 24)
-#define DDR2_DDQS_SHIFT                                        23
-#define DDR2_DDQS_MASK                                 (1 << 23)
-#define DYN_ODT_SHIFT                                  21
-#define DYN_ODT_MASK                                   (0x3 << 21)
-#define DDR_DISABLE_DLL_SHIFT                          20
-#define DDR_DISABLE_DLL_MASK                           (1 << 20)
-#define SDRAM_DRIVE_SHIFT                              18
-#define SDRAM_DRIVE_MASK                               (0x3 << 18)
-#define CWL_SHIFT                                      16
-#define CWL_MASK                                       (0x3 << 16)
-#define NARROW_MODE_SHIFT                              14
-#define NARROW_MODE_MASK                               (0x3 << 14)
-#define CL_SHIFT                                       10
-#define CL_MASK                                                (0xf << 10)
-#define ROWSIZE_SHIFT                                  7
-#define ROWSIZE_MASK                                   (0x7 << 7)
-#define IBANK_SHIFT                                    4
-#define IBANK_MASK                                     (0x7 << 4)
-#define EBANK_SHIFT                                    3
-#define EBANK_MASK                                     (1 << 3)
-#define PAGESIZE_SHIFT                                 0
-#define PAGESIZE_MASK                                  (0x7 << 0)
-
-/* SDRAM_CONFIG_2 */
-#define CS1NVMEN_SHIFT                                 30
-#define CS1NVMEN_MASK                                  (1 << 30)
-#define EBANK_POS_SHIFT                                        27
-#define EBANK_POS_MASK                                 (1 << 27)
-#define RDBNUM_SHIFT                                   4
-#define RDBNUM_MASK                                    (0x3 << 4)
-#define RDBSIZE_SHIFT                                  0
-#define RDBSIZE_MASK                                   (0x7 << 0)
-
-/* SDRAM_REFRESH_CONTROL */
-#define INITREF_DIS_SHIFT                              31
-#define INITREF_DIS_MASK                               (1 << 31)
-#define SRT_SHIFT                                      29
-#define SRT_MASK                                       (1 << 29)
-#define ASR_SHIFT                                      28
-#define ASR_MASK                                       (1 << 28)
-#define PASR_SHIFT                                     24
-#define PASR_MASK                                      (0x7 << 24)
-#define REFRESH_RATE_SHIFT                             0
-#define REFRESH_RATE_MASK                              (0xffff << 0)
-
-/* SDRAM_TIMING_1 */
-#define T_RTW_SHIFT                                    29
-#define T_RTW_MASK                                     (0x7 << 29)
-#define T_RP_SHIFT                                     25
-#define T_RP_MASK                                      (0xf << 25)
-#define T_RCD_SHIFT                                    21
-#define T_RCD_MASK                                     (0xf << 21)
-#define T_WR_SHIFT                                     17
-#define T_WR_MASK                                      (0xf << 17)
-#define T_RAS_SHIFT                                    12
-#define T_RAS_MASK                                     (0x1f << 12)
-#define T_RC_SHIFT                                     6
-#define T_RC_MASK                                      (0x3f << 6)
-#define T_RRD_SHIFT                                    3
-#define T_RRD_MASK                                     (0x7 << 3)
-#define T_WTR_SHIFT                                    0
-#define T_WTR_MASK                                     (0x7 << 0)
-
-/* SDRAM_TIMING_2 */
-#define T_XP_SHIFT                                     28
-#define T_XP_MASK                                      (0x7 << 28)
-#define T_ODT_SHIFT                                    25
-#define T_ODT_MASK                                     (0x7 << 25)
-#define T_XSNR_SHIFT                                   16
-#define T_XSNR_MASK                                    (0x1ff << 16)
-#define T_XSRD_SHIFT                                   6
-#define T_XSRD_MASK                                    (0x3ff << 6)
-#define T_RTP_SHIFT                                    3
-#define T_RTP_MASK                                     (0x7 << 3)
-#define T_CKE_SHIFT                                    0
-#define T_CKE_MASK                                     (0x7 << 0)
-
-/* SDRAM_TIMING_3 */
-#define T_PDLL_UL_SHIFT                                        28
-#define T_PDLL_UL_MASK                                 (0xf << 28)
-#define T_CSTA_SHIFT                                   24
-#define T_CSTA_MASK                                    (0xf << 24)
-#define T_CKESR_SHIFT                                  21
-#define T_CKESR_MASK                                   (0x7 << 21)
-#define ZQ_ZQCS_SHIFT                                  15
-#define ZQ_ZQCS_MASK                                   (0x3f << 15)
-#define T_TDQSCKMAX_SHIFT                              13
-#define T_TDQSCKMAX_MASK                               (0x3 << 13)
-#define T_RFC_SHIFT                                    4
-#define T_RFC_MASK                                     (0x1ff << 4)
-#define T_RAS_MAX_SHIFT                                        0
-#define T_RAS_MAX_MASK                                 (0xf << 0)
-
-/* POWER_MANAGEMENT_CONTROL */
-#define PD_TIM_SHIFT                                   12
-#define PD_TIM_MASK                                    (0xf << 12)
-#define DPD_EN_SHIFT                                   11
-#define DPD_EN_MASK                                    (1 << 11)
-#define LP_MODE_SHIFT                                  8
-#define LP_MODE_MASK                                   (0x7 << 8)
-#define SR_TIM_SHIFT                                   4
-#define SR_TIM_MASK                                    (0xf << 4)
-#define CS_TIM_SHIFT                                   0
-#define CS_TIM_MASK                                    (0xf << 0)
-
-/* LPDDR2_MODE_REG_DATA */
-#define VALUE_0_SHIFT                                  0
-#define VALUE_0_MASK                                   (0x7f << 0)
-
-/* LPDDR2_MODE_REG_CONFIG */
-#define CS_SHIFT                                       31
-#define CS_MASK                                                (1 << 31)
-#define REFRESH_EN_SHIFT                               30
-#define REFRESH_EN_MASK                                        (1 << 30)
-#define ADDRESS_SHIFT                                  0
-#define ADDRESS_MASK                                   (0xff << 0)
-
-/* OCP_CONFIG */
-#define SYS_THRESH_MAX_SHIFT                           24
-#define SYS_THRESH_MAX_MASK                            (0xf << 24)
-#define MPU_THRESH_MAX_SHIFT                           20
-#define MPU_THRESH_MAX_MASK                            (0xf << 20)
-#define LL_THRESH_MAX_SHIFT                            16
-#define LL_THRESH_MAX_MASK                             (0xf << 16)
-
-/* PERFORMANCE_COUNTER_1 */
-#define COUNTER1_SHIFT                                 0
-#define COUNTER1_MASK                                  (0xffffffff << 0)
-
-/* PERFORMANCE_COUNTER_2 */
-#define COUNTER2_SHIFT                                 0
-#define COUNTER2_MASK                                  (0xffffffff << 0)
-
-/* PERFORMANCE_COUNTER_CONFIG */
-#define CNTR2_MCONNID_EN_SHIFT                         31
-#define CNTR2_MCONNID_EN_MASK                          (1 << 31)
-#define CNTR2_REGION_EN_SHIFT                          30
-#define CNTR2_REGION_EN_MASK                           (1 << 30)
-#define CNTR2_CFG_SHIFT                                        16
-#define CNTR2_CFG_MASK                                 (0xf << 16)
-#define CNTR1_MCONNID_EN_SHIFT                         15
-#define CNTR1_MCONNID_EN_MASK                          (1 << 15)
-#define CNTR1_REGION_EN_SHIFT                          14
-#define CNTR1_REGION_EN_MASK                           (1 << 14)
-#define CNTR1_CFG_SHIFT                                        0
-#define CNTR1_CFG_MASK                                 (0xf << 0)
-
-/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
-#define MCONNID2_SHIFT                                 24
-#define MCONNID2_MASK                                  (0xff << 24)
-#define REGION_SEL2_SHIFT                              16
-#define REGION_SEL2_MASK                               (0x3 << 16)
-#define MCONNID1_SHIFT                                 8
-#define MCONNID1_MASK                                  (0xff << 8)
-#define REGION_SEL1_SHIFT                              0
-#define REGION_SEL1_MASK                               (0x3 << 0)
-
-/* PERFORMANCE_COUNTER_TIME */
-#define TOTAL_TIME_SHIFT                               0
-#define TOTAL_TIME_MASK                                        (0xffffffff << 0)
-
-/* DLL_CALIB_CTRL */
-#define ACK_WAIT_SHIFT                                 16
-#define ACK_WAIT_MASK                                  (0xf << 16)
-#define DLL_CALIB_INTERVAL_SHIFT                       0
-#define DLL_CALIB_INTERVAL_MASK                                (0x1ff << 0)
-
-/* END_OF_INTERRUPT */
-#define EOI_SHIFT                                      0
-#define EOI_MASK                                       (1 << 0)
-
-/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
-#define DNV_SYS_SHIFT                                  2
-#define DNV_SYS_MASK                                   (1 << 2)
-#define TA_SYS_SHIFT                                   1
-#define TA_SYS_MASK                                    (1 << 1)
-#define ERR_SYS_SHIFT                                  0
-#define ERR_SYS_MASK                                   (1 << 0)
-
-/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
-#define DNV_LL_SHIFT                                   2
-#define DNV_LL_MASK                                    (1 << 2)
-#define TA_LL_SHIFT                                    1
-#define TA_LL_MASK                                     (1 << 1)
-#define ERR_LL_SHIFT                                   0
-#define ERR_LL_MASK                                    (1 << 0)
-
-/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
-#define EN_DNV_SYS_SHIFT                               2
-#define EN_DNV_SYS_MASK                                        (1 << 2)
-#define EN_TA_SYS_SHIFT                                        1
-#define EN_TA_SYS_MASK                                 (1 << 1)
-#define EN_ERR_SYS_SHIFT                                       0
-#define EN_ERR_SYS_MASK                                        (1 << 0)
-
-/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
-#define EN_DNV_LL_SHIFT                                        2
-#define EN_DNV_LL_MASK                                 (1 << 2)
-#define EN_TA_LL_SHIFT                                 1
-#define EN_TA_LL_MASK                                  (1 << 1)
-#define EN_ERR_LL_SHIFT                                        0
-#define EN_ERR_LL_MASK                                 (1 << 0)
-
-/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
-#define ZQ_CS1EN_SHIFT                                 31
-#define ZQ_CS1EN_MASK                                  (1 << 31)
-#define ZQ_CS0EN_SHIFT                                 30
-#define ZQ_CS0EN_MASK                                  (1 << 30)
-#define ZQ_DUALCALEN_SHIFT                             29
-#define ZQ_DUALCALEN_MASK                              (1 << 29)
-#define ZQ_SFEXITEN_SHIFT                              28
-#define ZQ_SFEXITEN_MASK                               (1 << 28)
-#define ZQ_ZQINIT_MULT_SHIFT                           18
-#define ZQ_ZQINIT_MULT_MASK                            (0x3 << 18)
-#define ZQ_ZQCL_MULT_SHIFT                             16
-#define ZQ_ZQCL_MULT_MASK                              (0x3 << 16)
-#define ZQ_REFINTERVAL_SHIFT                           0
-#define ZQ_REFINTERVAL_MASK                            (0xffff << 0)
-
-/* TEMPERATURE_ALERT_CONFIG */
-#define TA_CS1EN_SHIFT                                 31
-#define TA_CS1EN_MASK                                  (1 << 31)
-#define TA_CS0EN_SHIFT                                 30
-#define TA_CS0EN_MASK                                  (1 << 30)
-#define TA_SFEXITEN_SHIFT                              28
-#define TA_SFEXITEN_MASK                               (1 << 28)
-#define TA_DEVWDT_SHIFT                                        26
-#define TA_DEVWDT_MASK                                 (0x3 << 26)
-#define TA_DEVCNT_SHIFT                                        24
-#define TA_DEVCNT_MASK                                 (0x3 << 24)
-#define TA_REFINTERVAL_SHIFT                           0
-#define TA_REFINTERVAL_MASK                            (0x3fffff << 0)
-
-/* OCP_ERROR_LOG */
-#define MADDRSPACE_SHIFT                               14
-#define MADDRSPACE_MASK                                        (0x3 << 14)
-#define MBURSTSEQ_SHIFT                                        11
-#define MBURSTSEQ_MASK                                 (0x7 << 11)
-#define MCMD_SHIFT                                     8
-#define MCMD_MASK                                      (0x7 << 8)
-#define MCONNID_SHIFT                                  0
-#define MCONNID_MASK                                   (0xff << 0)
-
-/* DDR_PHY_CTRL_1 - EMIF4D */
-#define DLL_SLAVE_DLY_CTRL_SHIFT_4D                    4
-#define DLL_SLAVE_DLY_CTRL_MASK_4D                     (0xFF << 4)
-#define READ_LATENCY_SHIFT_4D                          0
-#define READ_LATENCY_MASK_4D                           (0xf << 0)
-
-/* DDR_PHY_CTRL_1 - EMIF4D5 */
-#define DLL_HALF_DELAY_SHIFT_4D5                       21
-#define DLL_HALF_DELAY_MASK_4D5                                (1 << 21)
-#define READ_LATENCY_SHIFT_4D5                         0
-#define READ_LATENCY_MASK_4D5                          (0x1f << 0)
-
-/* DDR_PHY_CTRL_1_SHDW */
-#define DDR_PHY_CTRL_1_SHDW_SHIFT                      5
-#define DDR_PHY_CTRL_1_SHDW_MASK                       (0x7ffffff << 5)
-#define READ_LATENCY_SHDW_SHIFT                                0
-#define READ_LATENCY_SHDW_MASK                         (0x1f << 0)
+#include <linux/ti_emif.h>
 
 #ifndef __ASSEMBLY__
 /*
include/linux/ti_emif.h new file +558 -1
new file mode 100644
index 0000000..be26e7f
@@ -0,0 +1,558 @@
+/*
+ * Register defines for the EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson at ti.com)
+ *
+ * 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.
+ */
+#ifndef __TI_EMIF_H
+#define __TI_EMIF_H
+
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES                       6
+
+/* State of the core voltage */
+#define DDR_VOLTAGE_STABLE                             0
+#define DDR_VOLTAGE_RAMPING                            1
+
+/* Defines for timing De-rating */
+#define EMIF_NORMAL_TIMINGS                            0
+#define EMIF_DERATED_TIMINGS                           1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_READ_IDLE_LEN_VAL                         5
+
+/*
+ * forced read idle interval to be used when voltage
+ * is changed as part of DVFS/DPS - 1ms
+ */
+#define READ_IDLE_INTERVAL_DVFS                                (1*1000000)
+
+/*
+ * Forced read idle interval to be used when voltage is stable
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL                      (50*1000000)
+
+/* DLL calibration interval when voltage is NOT stable - 1us */
+#define DLL_CALIB_INTERVAL_DVFS                                (1*1000000)
+
+#define DLL_CALIB_ACK_WAIT_VAL                         5
+
+/* Interval between ZQCS commands - hw team recommended value */
+#define EMIF_ZQCS_INTERVAL_US                          (50*1000)
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define ZQ_SFEXITEN_ENABLE                             1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ */
+#define        ZQ_DUALCALEN_DISABLE                            0
+#define        ZQ_DUALCALEN_ENABLE                             1
+
+#define T_ZQCS_DEFAULT_NS                              90
+#define T_ZQCL_DEFAULT_NS                              360
+#define T_ZQINIT_DEFAULT_NS                            1000
+
+/* DPD_EN */
+#define DPD_DISABLE                                    0
+#define DPD_ENABLE                                     1
+
+/*
+ * Default values for the low-power entry to be used if not provided by user.
+ * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
+ * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
+ */
+#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE               2048
+#define EMIF_LP_MODE_TIMEOUT_POWER                     512
+#define EMIF_LP_MODE_FREQ_THRESHOLD                    400000000
+
+/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY         0x049FF000
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY      0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY      0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
+
+/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY                0x0E084200
+#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS      10000
+
+/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
+#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS            360
+
+#define EMIF_T_CSTA                                    3
+#define EMIF_T_PDLL_UL                                 128
+
+/* External PHY control registers magic values */
+#define EMIF_EXT_PHY_CTRL_1_VAL                                0x04020080
+#define EMIF_EXT_PHY_CTRL_5_VAL                                0x04010040
+#define EMIF_EXT_PHY_CTRL_6_VAL                                0x01004010
+#define EMIF_EXT_PHY_CTRL_7_VAL                                0x00001004
+#define EMIF_EXT_PHY_CTRL_8_VAL                                0x04010040
+#define EMIF_EXT_PHY_CTRL_9_VAL                                0x01004010
+#define EMIF_EXT_PHY_CTRL_10_VAL                       0x00001004
+#define EMIF_EXT_PHY_CTRL_11_VAL                       0x00000000
+#define EMIF_EXT_PHY_CTRL_12_VAL                       0x00000000
+#define EMIF_EXT_PHY_CTRL_13_VAL                       0x00000000
+#define EMIF_EXT_PHY_CTRL_14_VAL                       0x80080080
+#define EMIF_EXT_PHY_CTRL_15_VAL                       0x00800800
+#define EMIF_EXT_PHY_CTRL_16_VAL                       0x08102040
+#define EMIF_EXT_PHY_CTRL_17_VAL                       0x00000001
+#define EMIF_EXT_PHY_CTRL_18_VAL                       0x540A8150
+#define EMIF_EXT_PHY_CTRL_19_VAL                       0xA81502A0
+#define EMIF_EXT_PHY_CTRL_20_VAL                       0x002A0540
+#define EMIF_EXT_PHY_CTRL_21_VAL                       0x00000000
+#define EMIF_EXT_PHY_CTRL_22_VAL                       0x00000000
+#define EMIF_EXT_PHY_CTRL_23_VAL                       0x00000000
+#define EMIF_EXT_PHY_CTRL_24_VAL                       0x00000077
+
+#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS     1200
+
+/* Registers offset */
+#define EMIF_MODULE_ID_AND_REVISION                    0x0000
+#define EMIF_STATUS                                    0x0004
+#define EMIF_SDRAM_CONFIG                              0x0008
+#define EMIF_SDRAM_CONFIG_2                            0x000c
+#define EMIF_SDRAM_REFRESH_CONTROL                     0x0010
+#define EMIF_SDRAM_REFRESH_CTRL_SHDW                   0x0014
+#define EMIF_SDRAM_TIMING_1                            0x0018
+#define EMIF_SDRAM_TIMING_1_SHDW                       0x001c
+#define EMIF_SDRAM_TIMING_2                            0x0020
+#define EMIF_SDRAM_TIMING_2_SHDW                       0x0024
+#define EMIF_SDRAM_TIMING_3                            0x0028
+#define EMIF_SDRAM_TIMING_3_SHDW                       0x002c
+#define EMIF_LPDDR2_NVM_TIMING                         0x0030
+#define EMIF_LPDDR2_NVM_TIMING_SHDW                    0x0034
+#define EMIF_POWER_MANAGEMENT_CONTROL                  0x0038
+#define EMIF_POWER_MANAGEMENT_CTRL_SHDW                        0x003c
+#define EMIF_LPDDR2_MODE_REG_DATA                      0x0040
+#define EMIF_LPDDR2_MODE_REG_CONFIG                    0x0050
+#define EMIF_OCP_CONFIG                                        0x0054
+#define EMIF_OCP_CONFIG_VALUE_1                                0x0058
+#define EMIF_OCP_CONFIG_VALUE_2                                0x005c
+#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL           0x0060
+#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT         0x0064
+#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT      0x0068
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1       0x006c
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2       0x0070
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3       0x0074
+#define EMIF_PERFORMANCE_COUNTER_1                     0x0080
+#define EMIF_PERFORMANCE_COUNTER_2                     0x0084
+#define EMIF_PERFORMANCE_COUNTER_CONFIG                        0x0088
+#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT  0x008c
+#define EMIF_PERFORMANCE_COUNTER_TIME                  0x0090
+#define EMIF_MISC_REG                                  0x0094
+#define EMIF_DLL_CALIB_CTRL                            0x0098
+#define EMIF_DLL_CALIB_CTRL_SHDW                       0x009c
+#define EMIF_END_OF_INTERRUPT                          0x00a0
+#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS           0x00a4
+#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS               0x00a8
+#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS               0x00ac
+#define EMIF_LL_OCP_INTERRUPT_STATUS                   0x00b0
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET           0x00b4
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET               0x00b8
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR         0x00bc
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR             0x00c0
+#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG 0x00c8
+#define EMIF_TEMPERATURE_ALERT_CONFIG                  0x00cc
+#define EMIF_OCP_ERROR_LOG                             0x00d0
+#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW           0x00d4
+#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL          0x00d8
+#define EMIF_READ_WRITE_LEVELING_CONTROL               0x00dc
+#define EMIF_DDR_PHY_CTRL_1                            0x00e4
+#define EMIF_DDR_PHY_CTRL_1_SHDW                       0x00e8
+#define EMIF_DDR_PHY_CTRL_2                            0x00ec
+#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING      0x0100
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
+#define EMIF_READ_WRITE_EXECUTION_THRESHOLD            0x0120
+#define EMIF_COS_CONFIG                                        0x0124
+#define EMIF_PHY_STATUS_1                              0x0140
+#define EMIF_PHY_STATUS_2                              0x0144
+#define EMIF_PHY_STATUS_3                              0x0148
+#define EMIF_PHY_STATUS_4                              0x014c
+#define EMIF_PHY_STATUS_5                              0x0150
+#define EMIF_PHY_STATUS_6                              0x0154
+#define EMIF_PHY_STATUS_7                              0x0158
+#define EMIF_PHY_STATUS_8                              0x015c
+#define EMIF_PHY_STATUS_9                              0x0160
+#define EMIF_PHY_STATUS_10                             0x0164
+#define EMIF_PHY_STATUS_11                             0x0168
+#define EMIF_PHY_STATUS_12                             0x016c
+#define EMIF_PHY_STATUS_13                             0x0170
+#define EMIF_PHY_STATUS_14                             0x0174
+#define EMIF_PHY_STATUS_15                             0x0178
+#define EMIF_PHY_STATUS_16                             0x017c
+#define EMIF_PHY_STATUS_17                             0x0180
+#define EMIF_PHY_STATUS_18                             0x0184
+#define EMIF_PHY_STATUS_19                             0x0188
+#define EMIF_PHY_STATUS_20                             0x018c
+#define EMIF_PHY_STATUS_21                             0x0190
+#define EMIF_EXT_PHY_CTRL_1                            0x0200
+#define EMIF_EXT_PHY_CTRL_1_SHDW                       0x0204
+#define EMIF_EXT_PHY_CTRL_2                            0x0208
+#define EMIF_EXT_PHY_CTRL_2_SHDW                       0x020c
+#define EMIF_EXT_PHY_CTRL_3                            0x0210
+#define EMIF_EXT_PHY_CTRL_3_SHDW                       0x0214
+#define EMIF_EXT_PHY_CTRL_4                            0x0218
+#define EMIF_EXT_PHY_CTRL_4_SHDW                       0x021c
+#define EMIF_EXT_PHY_CTRL_5                            0x0220
+#define EMIF_EXT_PHY_CTRL_5_SHDW                       0x0224
+#define EMIF_EXT_PHY_CTRL_6                            0x0228
+#define EMIF_EXT_PHY_CTRL_6_SHDW                       0x022c
+#define EMIF_EXT_PHY_CTRL_7                            0x0230
+#define EMIF_EXT_PHY_CTRL_7_SHDW                       0x0234
+#define EMIF_EXT_PHY_CTRL_8                            0x0238
+#define EMIF_EXT_PHY_CTRL_8_SHDW                       0x023c
+#define EMIF_EXT_PHY_CTRL_9                            0x0240
+#define EMIF_EXT_PHY_CTRL_9_SHDW                       0x0244
+#define EMIF_EXT_PHY_CTRL_10                           0x0248
+#define EMIF_EXT_PHY_CTRL_10_SHDW                      0x024c
+#define EMIF_EXT_PHY_CTRL_11                           0x0250
+#define EMIF_EXT_PHY_CTRL_11_SHDW                      0x0254
+#define EMIF_EXT_PHY_CTRL_12                           0x0258
+#define EMIF_EXT_PHY_CTRL_12_SHDW                      0x025c
+#define EMIF_EXT_PHY_CTRL_13                           0x0260
+#define EMIF_EXT_PHY_CTRL_13_SHDW                      0x0264
+#define EMIF_EXT_PHY_CTRL_14                           0x0268
+#define EMIF_EXT_PHY_CTRL_14_SHDW                      0x026c
+#define EMIF_EXT_PHY_CTRL_15                           0x0270
+#define EMIF_EXT_PHY_CTRL_15_SHDW                      0x0274
+#define EMIF_EXT_PHY_CTRL_16                           0x0278
+#define EMIF_EXT_PHY_CTRL_16_SHDW                      0x027c
+#define EMIF_EXT_PHY_CTRL_17                           0x0280
+#define EMIF_EXT_PHY_CTRL_17_SHDW                      0x0284
+#define EMIF_EXT_PHY_CTRL_18                           0x0288
+#define EMIF_EXT_PHY_CTRL_18_SHDW                      0x028c
+#define EMIF_EXT_PHY_CTRL_19                           0x0290
+#define EMIF_EXT_PHY_CTRL_19_SHDW                      0x0294
+#define EMIF_EXT_PHY_CTRL_20                           0x0298
+#define EMIF_EXT_PHY_CTRL_20_SHDW                      0x029c
+#define EMIF_EXT_PHY_CTRL_21                           0x02a0
+#define EMIF_EXT_PHY_CTRL_21_SHDW                      0x02a4
+#define EMIF_EXT_PHY_CTRL_22                           0x02a8
+#define EMIF_EXT_PHY_CTRL_22_SHDW                      0x02ac
+#define EMIF_EXT_PHY_CTRL_23                           0x02b0
+#define EMIF_EXT_PHY_CTRL_23_SHDW                      0x02b4
+#define EMIF_EXT_PHY_CTRL_24                           0x02b8
+#define EMIF_EXT_PHY_CTRL_24_SHDW                      0x02bc
+#define EMIF_EXT_PHY_CTRL_25                           0x02c0
+#define EMIF_EXT_PHY_CTRL_25_SHDW                      0x02c4
+#define EMIF_EXT_PHY_CTRL_26                           0x02c8
+#define EMIF_EXT_PHY_CTRL_26_SHDW                      0x02cc
+#define EMIF_EXT_PHY_CTRL_27                           0x02d0
+#define EMIF_EXT_PHY_CTRL_27_SHDW                      0x02d4
+#define EMIF_EXT_PHY_CTRL_28                           0x02d8
+#define EMIF_EXT_PHY_CTRL_28_SHDW                      0x02dc
+#define EMIF_EXT_PHY_CTRL_29                           0x02e0
+#define EMIF_EXT_PHY_CTRL_29_SHDW                      0x02e4
+#define EMIF_EXT_PHY_CTRL_30                           0x02e8
+#define EMIF_EXT_PHY_CTRL_30_SHDW                      0x02ec
+
+/* Registers shifts and masks */
+
+/* EMIF_MODULE_ID_AND_REVISION */
+#define SCHEME_SHIFT                                   30
+#define SCHEME_MASK                                    (0x3 << 30)
+#define MODULE_ID_SHIFT                                        16
+#define MODULE_ID_MASK                                 (0xfff << 16)
+#define RTL_VERSION_SHIFT                              11
+#define RTL_VERSION_MASK                               (0x1f << 11)
+#define MAJOR_REVISION_SHIFT                           8
+#define MAJOR_REVISION_MASK                            (0x7 << 8)
+#define MINOR_REVISION_SHIFT                           0
+#define MINOR_REVISION_MASK                            (0x3f << 0)
+
+/* STATUS */
+#define BE_SHIFT                                       31
+#define BE_MASK                                                (1 << 31)
+#define DUAL_CLK_MODE_SHIFT                            30
+#define DUAL_CLK_MODE_MASK                             (1 << 30)
+#define FAST_INIT_SHIFT                                        29
+#define FAST_INIT_MASK                                 (1 << 29)
+#define RDLVLGATETO_SHIFT                              6
+#define RDLVLGATETO_MASK                               (1 << 6)
+#define RDLVLTO_SHIFT                                  5
+#define RDLVLTO_MASK                                   (1 << 5)
+#define WRLVLTO_SHIFT                                  4
+#define WRLVLTO_MASK                                   (1 << 4)
+#define PHY_DLL_READY_SHIFT                            2
+#define PHY_DLL_READY_MASK                             (1 << 2)
+
+/* SDRAM_CONFIG */
+#define SDRAM_TYPE_SHIFT                               29
+#define SDRAM_TYPE_MASK                                        (0x7 << 29)
+#define IBANK_POS_SHIFT                                        27
+#define IBANK_POS_MASK                                 (0x3 << 27)
+#define DDR_TERM_SHIFT                                 24
+#define DDR_TERM_MASK                                  (0x7 << 24)
+#define DDR2_DDQS_SHIFT                                        23
+#define DDR2_DDQS_MASK                                 (1 << 23)
+#define DYN_ODT_SHIFT                                  21
+#define DYN_ODT_MASK                                   (0x3 << 21)
+#define DDR_DISABLE_DLL_SHIFT                          20
+#define DDR_DISABLE_DLL_MASK                           (1 << 20)
+#define SDRAM_DRIVE_SHIFT                              18
+#define SDRAM_DRIVE_MASK                               (0x3 << 18)
+#define CWL_SHIFT                                      16
+#define CWL_MASK                                       (0x3 << 16)
+#define NARROW_MODE_SHIFT                              14
+#define NARROW_MODE_MASK                               (0x3 << 14)
+#define CL_SHIFT                                       10
+#define CL_MASK                                                (0xf << 10)
+#define ROWSIZE_SHIFT                                  7
+#define ROWSIZE_MASK                                   (0x7 << 7)
+#define IBANK_SHIFT                                    4
+#define IBANK_MASK                                     (0x7 << 4)
+#define EBANK_SHIFT                                    3
+#define EBANK_MASK                                     (1 << 3)
+#define PAGESIZE_SHIFT                                 0
+#define PAGESIZE_MASK                                  (0x7 << 0)
+
+/* SDRAM_CONFIG_2 */
+#define CS1NVMEN_SHIFT                                 30
+#define CS1NVMEN_MASK                                  (1 << 30)
+#define EBANK_POS_SHIFT                                        27
+#define EBANK_POS_MASK                                 (1 << 27)
+#define RDBNUM_SHIFT                                   4
+#define RDBNUM_MASK                                    (0x3 << 4)
+#define RDBSIZE_SHIFT                                  0
+#define RDBSIZE_MASK                                   (0x7 << 0)
+
+/* SDRAM_REFRESH_CONTROL */
+#define INITREF_DIS_SHIFT                              31
+#define INITREF_DIS_MASK                               (1 << 31)
+#define SRT_SHIFT                                      29
+#define SRT_MASK                                       (1 << 29)
+#define ASR_SHIFT                                      28
+#define ASR_MASK                                       (1 << 28)
+#define PASR_SHIFT                                     24
+#define PASR_MASK                                      (0x7 << 24)
+#define REFRESH_RATE_SHIFT                             0
+#define REFRESH_RATE_MASK                              (0xffff << 0)
+
+/* SDRAM_TIMING_1 */
+#define T_RTW_SHIFT                                    29
+#define T_RTW_MASK                                     (0x7 << 29)
+#define T_RP_SHIFT                                     25
+#define T_RP_MASK                                      (0xf << 25)
+#define T_RCD_SHIFT                                    21
+#define T_RCD_MASK                                     (0xf << 21)
+#define T_WR_SHIFT                                     17
+#define T_WR_MASK                                      (0xf << 17)
+#define T_RAS_SHIFT                                    12
+#define T_RAS_MASK                                     (0x1f << 12)
+#define T_RC_SHIFT                                     6
+#define T_RC_MASK                                      (0x3f << 6)
+#define T_RRD_SHIFT                                    3
+#define T_RRD_MASK                                     (0x7 << 3)
+#define T_WTR_SHIFT                                    0
+#define T_WTR_MASK                                     (0x7 << 0)
+
+/* SDRAM_TIMING_2 */
+#define T_XP_SHIFT                                     28
+#define T_XP_MASK                                      (0x7 << 28)
+#define T_ODT_SHIFT                                    25
+#define T_ODT_MASK                                     (0x7 << 25)
+#define T_XSNR_SHIFT                                   16
+#define T_XSNR_MASK                                    (0x1ff << 16)
+#define T_XSRD_SHIFT                                   6
+#define T_XSRD_MASK                                    (0x3ff << 6)
+#define T_RTP_SHIFT                                    3
+#define T_RTP_MASK                                     (0x7 << 3)
+#define T_CKE_SHIFT                                    0
+#define T_CKE_MASK                                     (0x7 << 0)
+
+/* SDRAM_TIMING_3 */
+#define T_PDLL_UL_SHIFT                                        28
+#define T_PDLL_UL_MASK                                 (0xf << 28)
+#define T_CSTA_SHIFT                                   24
+#define T_CSTA_MASK                                    (0xf << 24)
+#define T_CKESR_SHIFT                                  21
+#define T_CKESR_MASK                                   (0x7 << 21)
+#define ZQ_ZQCS_SHIFT                                  15
+#define ZQ_ZQCS_MASK                                   (0x3f << 15)
+#define T_TDQSCKMAX_SHIFT                              13
+#define T_TDQSCKMAX_MASK                               (0x3 << 13)
+#define T_RFC_SHIFT                                    4
+#define T_RFC_MASK                                     (0x1ff << 4)
+#define T_RAS_MAX_SHIFT                                        0
+#define T_RAS_MAX_MASK                                 (0xf << 0)
+
+/* POWER_MANAGEMENT_CONTROL */
+#define PD_TIM_SHIFT                                   12
+#define PD_TIM_MASK                                    (0xf << 12)
+#define DPD_EN_SHIFT                                   11
+#define DPD_EN_MASK                                    (1 << 11)
+#define LP_MODE_SHIFT                                  8
+#define LP_MODE_MASK                                   (0x7 << 8)
+#define SR_TIM_SHIFT                                   4
+#define SR_TIM_MASK                                    (0xf << 4)
+#define CS_TIM_SHIFT                                   0
+#define CS_TIM_MASK                                    (0xf << 0)
+
+/* LPDDR2_MODE_REG_DATA */
+#define VALUE_0_SHIFT                                  0
+#define VALUE_0_MASK                                   (0x7f << 0)
+
+/* LPDDR2_MODE_REG_CONFIG */
+#define CS_SHIFT                                       31
+#define CS_MASK                                                (1 << 31)
+#define REFRESH_EN_SHIFT                               30
+#define REFRESH_EN_MASK                                        (1 << 30)
+#define ADDRESS_SHIFT                                  0
+#define ADDRESS_MASK                                   (0xff << 0)
+
+/* OCP_CONFIG */
+#define SYS_THRESH_MAX_SHIFT                           24
+#define SYS_THRESH_MAX_MASK                            (0xf << 24)
+#define MPU_THRESH_MAX_SHIFT                           20
+#define MPU_THRESH_MAX_MASK                            (0xf << 20)
+#define LL_THRESH_MAX_SHIFT                            16
+#define LL_THRESH_MAX_MASK                             (0xf << 16)
+
+/* PERFORMANCE_COUNTER_1 */
+#define COUNTER1_SHIFT                                 0
+#define COUNTER1_MASK                                  (0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_2 */
+#define COUNTER2_SHIFT                                 0
+#define COUNTER2_MASK                                  (0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_CONFIG */
+#define CNTR2_MCONNID_EN_SHIFT                         31
+#define CNTR2_MCONNID_EN_MASK                          (1 << 31)
+#define CNTR2_REGION_EN_SHIFT                          30
+#define CNTR2_REGION_EN_MASK                           (1 << 30)
+#define CNTR2_CFG_SHIFT                                        16
+#define CNTR2_CFG_MASK                                 (0xf << 16)
+#define CNTR1_MCONNID_EN_SHIFT                         15
+#define CNTR1_MCONNID_EN_MASK                          (1 << 15)
+#define CNTR1_REGION_EN_SHIFT                          14
+#define CNTR1_REGION_EN_MASK                           (1 << 14)
+#define CNTR1_CFG_SHIFT                                        0
+#define CNTR1_CFG_MASK                                 (0xf << 0)
+
+/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
+#define MCONNID2_SHIFT                                 24
+#define MCONNID2_MASK                                  (0xff << 24)
+#define REGION_SEL2_SHIFT                              16
+#define REGION_SEL2_MASK                               (0x3 << 16)
+#define MCONNID1_SHIFT                                 8
+#define MCONNID1_MASK                                  (0xff << 8)
+#define REGION_SEL1_SHIFT                              0
+#define REGION_SEL1_MASK                               (0x3 << 0)
+
+/* PERFORMANCE_COUNTER_TIME */
+#define TOTAL_TIME_SHIFT                               0
+#define TOTAL_TIME_MASK                                        (0xffffffff << 0)
+
+/* DLL_CALIB_CTRL */
+#define ACK_WAIT_SHIFT                                 16
+#define ACK_WAIT_MASK                                  (0xf << 16)
+#define DLL_CALIB_INTERVAL_SHIFT                       0
+#define DLL_CALIB_INTERVAL_MASK                                (0x1ff << 0)
+
+/* END_OF_INTERRUPT */
+#define EOI_SHIFT                                      0
+#define EOI_MASK                                       (1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_SYS_SHIFT                                  2
+#define DNV_SYS_MASK                                   (1 << 2)
+#define TA_SYS_SHIFT                                   1
+#define TA_SYS_MASK                                    (1 << 1)
+#define ERR_SYS_SHIFT                                  0
+#define ERR_SYS_MASK                                   (1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_LL_SHIFT                                   2
+#define DNV_LL_MASK                                    (1 << 2)
+#define TA_LL_SHIFT                                    1
+#define TA_LL_MASK                                     (1 << 1)
+#define ERR_LL_SHIFT                                   0
+#define ERR_LL_MASK                                    (1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_SYS_SHIFT                               2
+#define EN_DNV_SYS_MASK                                        (1 << 2)
+#define EN_TA_SYS_SHIFT                                        1
+#define EN_TA_SYS_MASK                                 (1 << 1)
+#define EN_ERR_SYS_SHIFT                                       0
+#define EN_ERR_SYS_MASK                                        (1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_LL_SHIFT                                        2
+#define EN_DNV_LL_MASK                                 (1 << 2)
+#define EN_TA_LL_SHIFT                                 1
+#define EN_TA_LL_MASK                                  (1 << 1)
+#define EN_ERR_LL_SHIFT                                        0
+#define EN_ERR_LL_MASK                                 (1 << 0)
+
+/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
+#define ZQ_CS1EN_SHIFT                                 31
+#define ZQ_CS1EN_MASK                                  (1 << 31)
+#define ZQ_CS0EN_SHIFT                                 30
+#define ZQ_CS0EN_MASK                                  (1 << 30)
+#define ZQ_DUALCALEN_SHIFT                             29
+#define ZQ_DUALCALEN_MASK                              (1 << 29)
+#define ZQ_SFEXITEN_SHIFT                              28
+#define ZQ_SFEXITEN_MASK                               (1 << 28)
+#define ZQ_ZQINIT_MULT_SHIFT                           18
+#define ZQ_ZQINIT_MULT_MASK                            (0x3 << 18)
+#define ZQ_ZQCL_MULT_SHIFT                             16
+#define ZQ_ZQCL_MULT_MASK                              (0x3 << 16)
+#define ZQ_REFINTERVAL_SHIFT                           0
+#define ZQ_REFINTERVAL_MASK                            (0xffff << 0)
+
+/* TEMPERATURE_ALERT_CONFIG */
+#define TA_CS1EN_SHIFT                                 31
+#define TA_CS1EN_MASK                                  (1 << 31)
+#define TA_CS0EN_SHIFT                                 30
+#define TA_CS0EN_MASK                                  (1 << 30)
+#define TA_SFEXITEN_SHIFT                              28
+#define TA_SFEXITEN_MASK                               (1 << 28)
+#define TA_DEVWDT_SHIFT                                        26
+#define TA_DEVWDT_MASK                                 (0x3 << 26)
+#define TA_DEVCNT_SHIFT                                        24
+#define TA_DEVCNT_MASK                                 (0x3 << 24)
+#define TA_REFINTERVAL_SHIFT                           0
+#define TA_REFINTERVAL_MASK                            (0x3fffff << 0)
+
+/* OCP_ERROR_LOG */
+#define MADDRSPACE_SHIFT                               14
+#define MADDRSPACE_MASK                                        (0x3 << 14)
+#define MBURSTSEQ_SHIFT                                        11
+#define MBURSTSEQ_MASK                                 (0x7 << 11)
+#define MCMD_SHIFT                                     8
+#define MCMD_MASK                                      (0x7 << 8)
+#define MCONNID_SHIFT                                  0
+#define MCONNID_MASK                                   (0xff << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D */
+#define DLL_SLAVE_DLY_CTRL_SHIFT_4D                    4
+#define DLL_SLAVE_DLY_CTRL_MASK_4D                     (0xFF << 4)
+#define READ_LATENCY_SHIFT_4D                          0
+#define READ_LATENCY_MASK_4D                           (0xf << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D5 */
+#define DLL_HALF_DELAY_SHIFT_4D5                       21
+#define DLL_HALF_DELAY_MASK_4D5                                (1 << 21)
+#define READ_LATENCY_SHIFT_4D5                         0
+#define READ_LATENCY_MASK_4D5                          (0x1f << 0)
+
+/* DDR_PHY_CTRL_1_SHDW */
+#define DDR_PHY_CTRL_1_SHDW_SHIFT                      5
+#define DDR_PHY_CTRL_1_SHDW_MASK                       (0x7ffffff << 5)
+#define READ_LATENCY_SHDW_SHIFT                                0
+#define READ_LATENCY_SHDW_MASK                         (0x1f << 0)
+
+#endif /* __TI_EMIF_H */
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw

PATCH v3 1/9 memory: emif: Move EMIF register defines to include/linux/

In reply to Dave Gerlach

(You have not CC'ed Greg, Looping him)

Quoted 15 lines · Dave Gerlach

OMAP4 and AM33XX share the same EMIF controller IP. Although there are significant differences in the IP integration due to which AM33XX can't reuse the EMIF driver DVFS similar to OMAP4, it can definitely benefit by reusing the EMIF related macros defined in drivers/memory/emif.h.

In the current OMAP PM framework the PM code resides under arch/arm/mach-omap2/. To enable reuse of the register defines move the register defines in the emif header file to include/linux so that both the EMIF driver and the AM33XX PM code can benefit.

Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Aneesh V <[email protected]>
Quoted 6 lines
---
 drivers/memory/emif.h   |  543 +--------------------------------------------
 include/linux/ti_emif.h |  558 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 559 insertions(+), 542 deletions(-)
 create mode 100644 include/linux/ti_emif.h

For file movement or some part of file movement, while formating patch, use "git format-patch -C" so that only delta change will appear in the patch.

The patch as such is fine by me.

Greg,
Your ack is needed on this patch so that it can go along with the series. Subsequent patch from this series use the register defines from this patch.

Quoted 1,119 lines
drivers/memory/emif.h +1 -542
index bfe08ba..8214f07 100644
@@ -12,548 +12,7 @@
 #ifndef __EMIF_H
 #define __EMIF_H
 
-/*
- * Maximum number of different frequencies supported by EMIF driver
- * Determines the number of entries in the pointer array for register
- * cache
- */
-#define EMIF_MAX_NUM_FREQUENCIES			6
-
-/* State of the core voltage */
-#define DDR_VOLTAGE_STABLE				0
-#define DDR_VOLTAGE_RAMPING				1
-
-/* Defines for timing De-rating */
-#define EMIF_NORMAL_TIMINGS				0
-#define EMIF_DERATED_TIMINGS				1
-
-/* Length of the forced read idle period in terms of cycles */
-#define EMIF_READ_IDLE_LEN_VAL				5
-
-/*
- * forced read idle interval to be used when voltage
- * is changed as part of DVFS/DPS - 1ms
- */
-#define READ_IDLE_INTERVAL_DVFS				(1*1000000)
-
-/*
- * Forced read idle interval to be used when voltage is stable
- * 50us - or maximum value will do
- */
-#define READ_IDLE_INTERVAL_NORMAL			(50*1000000)
-
-/* DLL calibration interval when voltage is NOT stable - 1us */
-#define DLL_CALIB_INTERVAL_DVFS				(1*1000000)
-
-#define DLL_CALIB_ACK_WAIT_VAL				5
-
-/* Interval between ZQCS commands - hw team recommended value */
-#define EMIF_ZQCS_INTERVAL_US				(50*1000)
-/* Enable ZQ Calibration on exiting Self-refresh */
-#define ZQ_SFEXITEN_ENABLE				1
-/*
- * ZQ Calibration simultaneously on both chip-selects:
- * Needs one calibration resistor per CS
- */
-#define	ZQ_DUALCALEN_DISABLE				0
-#define	ZQ_DUALCALEN_ENABLE				1
-
-#define T_ZQCS_DEFAULT_NS				90
-#define T_ZQCL_DEFAULT_NS				360
-#define T_ZQINIT_DEFAULT_NS				1000
-
-/* DPD_EN */
-#define DPD_DISABLE					0
-#define DPD_ENABLE					1
-
-/*
- * Default values for the low-power entry to be used if not provided by user.
- * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
- * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
- */
-#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE		2048
-#define EMIF_LP_MODE_TIMEOUT_POWER			512
-#define EMIF_LP_MODE_FREQ_THRESHOLD			400000000
-
-/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
-#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY		0x049FF000
-#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY	0x41
-#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY	0x80
-#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
-
-/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
-#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY		0x0E084200
-#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS	10000
-
-/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
-#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS		360
-
-#define EMIF_T_CSTA					3
-#define EMIF_T_PDLL_UL					128
-
-/* External PHY control registers magic values */
-#define EMIF_EXT_PHY_CTRL_1_VAL				0x04020080
-#define EMIF_EXT_PHY_CTRL_5_VAL				0x04010040
-#define EMIF_EXT_PHY_CTRL_6_VAL				0x01004010
-#define EMIF_EXT_PHY_CTRL_7_VAL				0x00001004
-#define EMIF_EXT_PHY_CTRL_8_VAL				0x04010040
-#define EMIF_EXT_PHY_CTRL_9_VAL				0x01004010
-#define EMIF_EXT_PHY_CTRL_10_VAL			0x00001004
-#define EMIF_EXT_PHY_CTRL_11_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_12_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_13_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_14_VAL			0x80080080
-#define EMIF_EXT_PHY_CTRL_15_VAL			0x00800800
-#define EMIF_EXT_PHY_CTRL_16_VAL			0x08102040
-#define EMIF_EXT_PHY_CTRL_17_VAL			0x00000001
-#define EMIF_EXT_PHY_CTRL_18_VAL			0x540A8150
-#define EMIF_EXT_PHY_CTRL_19_VAL			0xA81502A0
-#define EMIF_EXT_PHY_CTRL_20_VAL			0x002A0540
-#define EMIF_EXT_PHY_CTRL_21_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_22_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_23_VAL			0x00000000
-#define EMIF_EXT_PHY_CTRL_24_VAL			0x00000077
-
-#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS	1200
-
-/* Registers offset */
-#define EMIF_MODULE_ID_AND_REVISION			0x0000
-#define EMIF_STATUS					0x0004
-#define EMIF_SDRAM_CONFIG				0x0008
-#define EMIF_SDRAM_CONFIG_2				0x000c
-#define EMIF_SDRAM_REFRESH_CONTROL			0x0010
-#define EMIF_SDRAM_REFRESH_CTRL_SHDW			0x0014
-#define EMIF_SDRAM_TIMING_1				0x0018
-#define EMIF_SDRAM_TIMING_1_SHDW			0x001c
-#define EMIF_SDRAM_TIMING_2				0x0020
-#define EMIF_SDRAM_TIMING_2_SHDW			0x0024
-#define EMIF_SDRAM_TIMING_3				0x0028
-#define EMIF_SDRAM_TIMING_3_SHDW			0x002c
-#define EMIF_LPDDR2_NVM_TIMING				0x0030
-#define EMIF_LPDDR2_NVM_TIMING_SHDW			0x0034
-#define EMIF_POWER_MANAGEMENT_CONTROL			0x0038
-#define EMIF_POWER_MANAGEMENT_CTRL_SHDW			0x003c
-#define EMIF_LPDDR2_MODE_REG_DATA			0x0040
-#define EMIF_LPDDR2_MODE_REG_CONFIG			0x0050
-#define EMIF_OCP_CONFIG					0x0054
-#define EMIF_OCP_CONFIG_VALUE_1				0x0058
-#define EMIF_OCP_CONFIG_VALUE_2				0x005c
-#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL		0x0060
-#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT		0x0064
-#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT	0x0068
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1	0x006c
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2	0x0070
-#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3	0x0074
-#define EMIF_PERFORMANCE_COUNTER_1			0x0080
-#define EMIF_PERFORMANCE_COUNTER_2			0x0084
-#define EMIF_PERFORMANCE_COUNTER_CONFIG			0x0088
-#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT	0x008c
-#define EMIF_PERFORMANCE_COUNTER_TIME			0x0090
-#define EMIF_MISC_REG					0x0094
-#define EMIF_DLL_CALIB_CTRL				0x0098
-#define EMIF_DLL_CALIB_CTRL_SHDW			0x009c
-#define EMIF_END_OF_INTERRUPT				0x00a0
-#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS		0x00a4
-#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS		0x00a8
-#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS		0x00ac
-#define EMIF_LL_OCP_INTERRUPT_STATUS			0x00b0
-#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET		0x00b4
-#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET		0x00b8
-#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR		0x00bc
-#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR		0x00c0
-#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG	0x00c8
-#define EMIF_TEMPERATURE_ALERT_CONFIG			0x00cc
-#define EMIF_OCP_ERROR_LOG				0x00d0
-#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW		0x00d4
-#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL		0x00d8
-#define EMIF_READ_WRITE_LEVELING_CONTROL		0x00dc
-#define EMIF_DDR_PHY_CTRL_1				0x00e4
-#define EMIF_DDR_PHY_CTRL_1_SHDW			0x00e8
-#define EMIF_DDR_PHY_CTRL_2				0x00ec
-#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING	0x0100
-#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
-#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
-#define EMIF_READ_WRITE_EXECUTION_THRESHOLD		0x0120
-#define EMIF_COS_CONFIG					0x0124
-#define EMIF_PHY_STATUS_1				0x0140
-#define EMIF_PHY_STATUS_2				0x0144
-#define EMIF_PHY_STATUS_3				0x0148
-#define EMIF_PHY_STATUS_4				0x014c
-#define EMIF_PHY_STATUS_5				0x0150
-#define EMIF_PHY_STATUS_6				0x0154
-#define EMIF_PHY_STATUS_7				0x0158
-#define EMIF_PHY_STATUS_8				0x015c
-#define EMIF_PHY_STATUS_9				0x0160
-#define EMIF_PHY_STATUS_10				0x0164
-#define EMIF_PHY_STATUS_11				0x0168
-#define EMIF_PHY_STATUS_12				0x016c
-#define EMIF_PHY_STATUS_13				0x0170
-#define EMIF_PHY_STATUS_14				0x0174
-#define EMIF_PHY_STATUS_15				0x0178
-#define EMIF_PHY_STATUS_16				0x017c
-#define EMIF_PHY_STATUS_17				0x0180
-#define EMIF_PHY_STATUS_18				0x0184
-#define EMIF_PHY_STATUS_19				0x0188
-#define EMIF_PHY_STATUS_20				0x018c
-#define EMIF_PHY_STATUS_21				0x0190
-#define EMIF_EXT_PHY_CTRL_1				0x0200
-#define EMIF_EXT_PHY_CTRL_1_SHDW			0x0204
-#define EMIF_EXT_PHY_CTRL_2				0x0208
-#define EMIF_EXT_PHY_CTRL_2_SHDW			0x020c
-#define EMIF_EXT_PHY_CTRL_3				0x0210
-#define EMIF_EXT_PHY_CTRL_3_SHDW			0x0214
-#define EMIF_EXT_PHY_CTRL_4				0x0218
-#define EMIF_EXT_PHY_CTRL_4_SHDW			0x021c
-#define EMIF_EXT_PHY_CTRL_5				0x0220
-#define EMIF_EXT_PHY_CTRL_5_SHDW			0x0224
-#define EMIF_EXT_PHY_CTRL_6				0x0228
-#define EMIF_EXT_PHY_CTRL_6_SHDW			0x022c
-#define EMIF_EXT_PHY_CTRL_7				0x0230
-#define EMIF_EXT_PHY_CTRL_7_SHDW			0x0234
-#define EMIF_EXT_PHY_CTRL_8				0x0238
-#define EMIF_EXT_PHY_CTRL_8_SHDW			0x023c
-#define EMIF_EXT_PHY_CTRL_9				0x0240
-#define EMIF_EXT_PHY_CTRL_9_SHDW			0x0244
-#define EMIF_EXT_PHY_CTRL_10				0x0248
-#define EMIF_EXT_PHY_CTRL_10_SHDW			0x024c
-#define EMIF_EXT_PHY_CTRL_11				0x0250
-#define EMIF_EXT_PHY_CTRL_11_SHDW			0x0254
-#define EMIF_EXT_PHY_CTRL_12				0x0258
-#define EMIF_EXT_PHY_CTRL_12_SHDW			0x025c
-#define EMIF_EXT_PHY_CTRL_13				0x0260
-#define EMIF_EXT_PHY_CTRL_13_SHDW			0x0264
-#define EMIF_EXT_PHY_CTRL_14				0x0268
-#define EMIF_EXT_PHY_CTRL_14_SHDW			0x026c
-#define EMIF_EXT_PHY_CTRL_15				0x0270
-#define EMIF_EXT_PHY_CTRL_15_SHDW			0x0274
-#define EMIF_EXT_PHY_CTRL_16				0x0278
-#define EMIF_EXT_PHY_CTRL_16_SHDW			0x027c
-#define EMIF_EXT_PHY_CTRL_17				0x0280
-#define EMIF_EXT_PHY_CTRL_17_SHDW			0x0284
-#define EMIF_EXT_PHY_CTRL_18				0x0288
-#define EMIF_EXT_PHY_CTRL_18_SHDW			0x028c
-#define EMIF_EXT_PHY_CTRL_19				0x0290
-#define EMIF_EXT_PHY_CTRL_19_SHDW			0x0294
-#define EMIF_EXT_PHY_CTRL_20				0x0298
-#define EMIF_EXT_PHY_CTRL_20_SHDW			0x029c
-#define EMIF_EXT_PHY_CTRL_21				0x02a0
-#define EMIF_EXT_PHY_CTRL_21_SHDW			0x02a4
-#define EMIF_EXT_PHY_CTRL_22				0x02a8
-#define EMIF_EXT_PHY_CTRL_22_SHDW			0x02ac
-#define EMIF_EXT_PHY_CTRL_23				0x02b0
-#define EMIF_EXT_PHY_CTRL_23_SHDW			0x02b4
-#define EMIF_EXT_PHY_CTRL_24				0x02b8
-#define EMIF_EXT_PHY_CTRL_24_SHDW			0x02bc
-#define EMIF_EXT_PHY_CTRL_25				0x02c0
-#define EMIF_EXT_PHY_CTRL_25_SHDW			0x02c4
-#define EMIF_EXT_PHY_CTRL_26				0x02c8
-#define EMIF_EXT_PHY_CTRL_26_SHDW			0x02cc
-#define EMIF_EXT_PHY_CTRL_27				0x02d0
-#define EMIF_EXT_PHY_CTRL_27_SHDW			0x02d4
-#define EMIF_EXT_PHY_CTRL_28				0x02d8
-#define EMIF_EXT_PHY_CTRL_28_SHDW			0x02dc
-#define EMIF_EXT_PHY_CTRL_29				0x02e0
-#define EMIF_EXT_PHY_CTRL_29_SHDW			0x02e4
-#define EMIF_EXT_PHY_CTRL_30				0x02e8
-#define EMIF_EXT_PHY_CTRL_30_SHDW			0x02ec
-
-/* Registers shifts and masks */
-
-/* EMIF_MODULE_ID_AND_REVISION */
-#define SCHEME_SHIFT					30
-#define SCHEME_MASK					(0x3 << 30)
-#define MODULE_ID_SHIFT					16
-#define MODULE_ID_MASK					(0xfff << 16)
-#define RTL_VERSION_SHIFT				11
-#define RTL_VERSION_MASK				(0x1f << 11)
-#define MAJOR_REVISION_SHIFT				8
-#define MAJOR_REVISION_MASK				(0x7 << 8)
-#define MINOR_REVISION_SHIFT				0
-#define MINOR_REVISION_MASK				(0x3f << 0)
-
-/* STATUS */
-#define BE_SHIFT					31
-#define BE_MASK						(1 << 31)
-#define DUAL_CLK_MODE_SHIFT				30
-#define DUAL_CLK_MODE_MASK				(1 << 30)
-#define FAST_INIT_SHIFT					29
-#define FAST_INIT_MASK					(1 << 29)
-#define RDLVLGATETO_SHIFT				6
-#define RDLVLGATETO_MASK				(1 << 6)
-#define RDLVLTO_SHIFT					5
-#define RDLVLTO_MASK					(1 << 5)
-#define WRLVLTO_SHIFT					4
-#define WRLVLTO_MASK					(1 << 4)
-#define PHY_DLL_READY_SHIFT				2
-#define PHY_DLL_READY_MASK				(1 << 2)
-
-/* SDRAM_CONFIG */
-#define SDRAM_TYPE_SHIFT				29
-#define SDRAM_TYPE_MASK					(0x7 << 29)
-#define IBANK_POS_SHIFT					27
-#define IBANK_POS_MASK					(0x3 << 27)
-#define DDR_TERM_SHIFT					24
-#define DDR_TERM_MASK					(0x7 << 24)
-#define DDR2_DDQS_SHIFT					23
-#define DDR2_DDQS_MASK					(1 << 23)
-#define DYN_ODT_SHIFT					21
-#define DYN_ODT_MASK					(0x3 << 21)
-#define DDR_DISABLE_DLL_SHIFT				20
-#define DDR_DISABLE_DLL_MASK				(1 << 20)
-#define SDRAM_DRIVE_SHIFT				18
-#define SDRAM_DRIVE_MASK				(0x3 << 18)
-#define CWL_SHIFT					16
-#define CWL_MASK					(0x3 << 16)
-#define NARROW_MODE_SHIFT				14
-#define NARROW_MODE_MASK				(0x3 << 14)
-#define CL_SHIFT					10
-#define CL_MASK						(0xf << 10)
-#define ROWSIZE_SHIFT					7
-#define ROWSIZE_MASK					(0x7 << 7)
-#define IBANK_SHIFT					4
-#define IBANK_MASK					(0x7 << 4)
-#define EBANK_SHIFT					3
-#define EBANK_MASK					(1 << 3)
-#define PAGESIZE_SHIFT					0
-#define PAGESIZE_MASK					(0x7 << 0)
-
-/* SDRAM_CONFIG_2 */
-#define CS1NVMEN_SHIFT					30
-#define CS1NVMEN_MASK					(1 << 30)
-#define EBANK_POS_SHIFT					27
-#define EBANK_POS_MASK					(1 << 27)
-#define RDBNUM_SHIFT					4
-#define RDBNUM_MASK					(0x3 << 4)
-#define RDBSIZE_SHIFT					0
-#define RDBSIZE_MASK					(0x7 << 0)
-
-/* SDRAM_REFRESH_CONTROL */
-#define INITREF_DIS_SHIFT				31
-#define INITREF_DIS_MASK				(1 << 31)
-#define SRT_SHIFT					29
-#define SRT_MASK					(1 << 29)
-#define ASR_SHIFT					28
-#define ASR_MASK					(1 << 28)
-#define PASR_SHIFT					24
-#define PASR_MASK					(0x7 << 24)
-#define REFRESH_RATE_SHIFT				0
-#define REFRESH_RATE_MASK				(0xffff << 0)
-
-/* SDRAM_TIMING_1 */
-#define T_RTW_SHIFT					29
-#define T_RTW_MASK					(0x7 << 29)
-#define T_RP_SHIFT					25
-#define T_RP_MASK					(0xf << 25)
-#define T_RCD_SHIFT					21
-#define T_RCD_MASK					(0xf << 21)
-#define T_WR_SHIFT					17
-#define T_WR_MASK					(0xf << 17)
-#define T_RAS_SHIFT					12
-#define T_RAS_MASK					(0x1f << 12)
-#define T_RC_SHIFT					6
-#define T_RC_MASK					(0x3f << 6)
-#define T_RRD_SHIFT					3
-#define T_RRD_MASK					(0x7 << 3)
-#define T_WTR_SHIFT					0
-#define T_WTR_MASK					(0x7 << 0)
-
-/* SDRAM_TIMING_2 */
-#define T_XP_SHIFT					28
-#define T_XP_MASK					(0x7 << 28)
-#define T_ODT_SHIFT					25
-#define T_ODT_MASK					(0x7 << 25)
-#define T_XSNR_SHIFT					16
-#define T_XSNR_MASK					(0x1ff << 16)
-#define T_XSRD_SHIFT					6
-#define T_XSRD_MASK					(0x3ff << 6)
-#define T_RTP_SHIFT					3
-#define T_RTP_MASK					(0x7 << 3)
-#define T_CKE_SHIFT					0
-#define T_CKE_MASK					(0x7 << 0)
-
-/* SDRAM_TIMING_3 */
-#define T_PDLL_UL_SHIFT					28
-#define T_PDLL_UL_MASK					(0xf << 28)
-#define T_CSTA_SHIFT					24
-#define T_CSTA_MASK					(0xf << 24)
-#define T_CKESR_SHIFT					21
-#define T_CKESR_MASK					(0x7 << 21)
-#define ZQ_ZQCS_SHIFT					15
-#define ZQ_ZQCS_MASK					(0x3f << 15)
-#define T_TDQSCKMAX_SHIFT				13
-#define T_TDQSCKMAX_MASK				(0x3 << 13)
-#define T_RFC_SHIFT					4
-#define T_RFC_MASK					(0x1ff << 4)
-#define T_RAS_MAX_SHIFT					0
-#define T_RAS_MAX_MASK					(0xf << 0)
-
-/* POWER_MANAGEMENT_CONTROL */
-#define PD_TIM_SHIFT					12
-#define PD_TIM_MASK					(0xf << 12)
-#define DPD_EN_SHIFT					11
-#define DPD_EN_MASK					(1 << 11)
-#define LP_MODE_SHIFT					8
-#define LP_MODE_MASK					(0x7 << 8)
-#define SR_TIM_SHIFT					4
-#define SR_TIM_MASK					(0xf << 4)
-#define CS_TIM_SHIFT					0
-#define CS_TIM_MASK					(0xf << 0)
-
-/* LPDDR2_MODE_REG_DATA */
-#define VALUE_0_SHIFT					0
-#define VALUE_0_MASK					(0x7f << 0)
-
-/* LPDDR2_MODE_REG_CONFIG */
-#define CS_SHIFT					31
-#define CS_MASK						(1 << 31)
-#define REFRESH_EN_SHIFT				30
-#define REFRESH_EN_MASK					(1 << 30)
-#define ADDRESS_SHIFT					0
-#define ADDRESS_MASK					(0xff << 0)
-
-/* OCP_CONFIG */
-#define SYS_THRESH_MAX_SHIFT				24
-#define SYS_THRESH_MAX_MASK				(0xf << 24)
-#define MPU_THRESH_MAX_SHIFT				20
-#define MPU_THRESH_MAX_MASK				(0xf << 20)
-#define LL_THRESH_MAX_SHIFT				16
-#define LL_THRESH_MAX_MASK				(0xf << 16)
-
-/* PERFORMANCE_COUNTER_1 */
-#define COUNTER1_SHIFT					0
-#define COUNTER1_MASK					(0xffffffff << 0)
-
-/* PERFORMANCE_COUNTER_2 */
-#define COUNTER2_SHIFT					0
-#define COUNTER2_MASK					(0xffffffff << 0)
-
-/* PERFORMANCE_COUNTER_CONFIG */
-#define CNTR2_MCONNID_EN_SHIFT				31
-#define CNTR2_MCONNID_EN_MASK				(1 << 31)
-#define CNTR2_REGION_EN_SHIFT				30
-#define CNTR2_REGION_EN_MASK				(1 << 30)
-#define CNTR2_CFG_SHIFT					16
-#define CNTR2_CFG_MASK					(0xf << 16)
-#define CNTR1_MCONNID_EN_SHIFT				15
-#define CNTR1_MCONNID_EN_MASK				(1 << 15)
-#define CNTR1_REGION_EN_SHIFT				14
-#define CNTR1_REGION_EN_MASK				(1 << 14)
-#define CNTR1_CFG_SHIFT					0
-#define CNTR1_CFG_MASK					(0xf << 0)
-
-/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
-#define MCONNID2_SHIFT					24
-#define MCONNID2_MASK					(0xff << 24)
-#define REGION_SEL2_SHIFT				16
-#define REGION_SEL2_MASK				(0x3 << 16)
-#define MCONNID1_SHIFT					8
-#define MCONNID1_MASK					(0xff << 8)
-#define REGION_SEL1_SHIFT				0
-#define REGION_SEL1_MASK				(0x3 << 0)
-
-/* PERFORMANCE_COUNTER_TIME */
-#define TOTAL_TIME_SHIFT				0
-#define TOTAL_TIME_MASK					(0xffffffff << 0)
-
-/* DLL_CALIB_CTRL */
-#define ACK_WAIT_SHIFT					16
-#define ACK_WAIT_MASK					(0xf << 16)
-#define DLL_CALIB_INTERVAL_SHIFT			0
-#define DLL_CALIB_INTERVAL_MASK				(0x1ff << 0)
-
-/* END_OF_INTERRUPT */
-#define EOI_SHIFT					0
-#define EOI_MASK					(1 << 0)
-
-/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
-#define DNV_SYS_SHIFT					2
-#define DNV_SYS_MASK					(1 << 2)
-#define TA_SYS_SHIFT					1
-#define TA_SYS_MASK					(1 << 1)
-#define ERR_SYS_SHIFT					0
-#define ERR_SYS_MASK					(1 << 0)
-
-/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
-#define DNV_LL_SHIFT					2
-#define DNV_LL_MASK					(1 << 2)
-#define TA_LL_SHIFT					1
-#define TA_LL_MASK					(1 << 1)
-#define ERR_LL_SHIFT					0
-#define ERR_LL_MASK					(1 << 0)
-
-/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
-#define EN_DNV_SYS_SHIFT				2
-#define EN_DNV_SYS_MASK					(1 << 2)
-#define EN_TA_SYS_SHIFT					1
-#define EN_TA_SYS_MASK					(1 << 1)
-#define EN_ERR_SYS_SHIFT					0
-#define EN_ERR_SYS_MASK					(1 << 0)
-
-/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
-#define EN_DNV_LL_SHIFT					2
-#define EN_DNV_LL_MASK					(1 << 2)
-#define EN_TA_LL_SHIFT					1
-#define EN_TA_LL_MASK					(1 << 1)
-#define EN_ERR_LL_SHIFT					0
-#define EN_ERR_LL_MASK					(1 << 0)
-
-/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
-#define ZQ_CS1EN_SHIFT					31
-#define ZQ_CS1EN_MASK					(1 << 31)
-#define ZQ_CS0EN_SHIFT					30
-#define ZQ_CS0EN_MASK					(1 << 30)
-#define ZQ_DUALCALEN_SHIFT				29
-#define ZQ_DUALCALEN_MASK				(1 << 29)
-#define ZQ_SFEXITEN_SHIFT				28
-#define ZQ_SFEXITEN_MASK				(1 << 28)
-#define ZQ_ZQINIT_MULT_SHIFT				18
-#define ZQ_ZQINIT_MULT_MASK				(0x3 << 18)
-#define ZQ_ZQCL_MULT_SHIFT				16
-#define ZQ_ZQCL_MULT_MASK				(0x3 << 16)
-#define ZQ_REFINTERVAL_SHIFT				0
-#define ZQ_REFINTERVAL_MASK				(0xffff << 0)
-
-/* TEMPERATURE_ALERT_CONFIG */
-#define TA_CS1EN_SHIFT					31
-#define TA_CS1EN_MASK					(1 << 31)
-#define TA_CS0EN_SHIFT					30
-#define TA_CS0EN_MASK					(1 << 30)
-#define TA_SFEXITEN_SHIFT				28
-#define TA_SFEXITEN_MASK				(1 << 28)
-#define TA_DEVWDT_SHIFT					26
-#define TA_DEVWDT_MASK					(0x3 << 26)
-#define TA_DEVCNT_SHIFT					24
-#define TA_DEVCNT_MASK					(0x3 << 24)
-#define TA_REFINTERVAL_SHIFT				0
-#define TA_REFINTERVAL_MASK				(0x3fffff << 0)
-
-/* OCP_ERROR_LOG */
-#define MADDRSPACE_SHIFT				14
-#define MADDRSPACE_MASK					(0x3 << 14)
-#define MBURSTSEQ_SHIFT					11
-#define MBURSTSEQ_MASK					(0x7 << 11)
-#define MCMD_SHIFT					8
-#define MCMD_MASK					(0x7 << 8)
-#define MCONNID_SHIFT					0
-#define MCONNID_MASK					(0xff << 0)
-
-/* DDR_PHY_CTRL_1 - EMIF4D */
-#define DLL_SLAVE_DLY_CTRL_SHIFT_4D			4
-#define DLL_SLAVE_DLY_CTRL_MASK_4D			(0xFF << 4)
-#define READ_LATENCY_SHIFT_4D				0
-#define READ_LATENCY_MASK_4D				(0xf << 0)
-
-/* DDR_PHY_CTRL_1 - EMIF4D5 */
-#define DLL_HALF_DELAY_SHIFT_4D5			21
-#define DLL_HALF_DELAY_MASK_4D5				(1 << 21)
-#define READ_LATENCY_SHIFT_4D5				0
-#define READ_LATENCY_MASK_4D5				(0x1f << 0)
-
-/* DDR_PHY_CTRL_1_SHDW */
-#define DDR_PHY_CTRL_1_SHDW_SHIFT			5
-#define DDR_PHY_CTRL_1_SHDW_MASK			(0x7ffffff << 5)
-#define READ_LATENCY_SHDW_SHIFT				0
-#define READ_LATENCY_SHDW_MASK				(0x1f << 0)
+#include <linux/ti_emif.h>
 
 #ifndef __ASSEMBLY__
 /*
include/linux/ti_emif.h new file +558 -0
new file mode 100644
index 0000000..be26e7f
@@ -0,0 +1,558 @@
+/*
+ * Register defines for the EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson at ti.com)
+ *
+ * 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.
+ */
+#ifndef __TI_EMIF_H
+#define __TI_EMIF_H
+
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES			6
+
+/* State of the core voltage */
+#define DDR_VOLTAGE_STABLE				0
+#define DDR_VOLTAGE_RAMPING				1
+
+/* Defines for timing De-rating */
+#define EMIF_NORMAL_TIMINGS				0
+#define EMIF_DERATED_TIMINGS				1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_READ_IDLE_LEN_VAL				5
+
+/*
+ * forced read idle interval to be used when voltage
+ * is changed as part of DVFS/DPS - 1ms
+ */
+#define READ_IDLE_INTERVAL_DVFS				(1*1000000)
+
+/*
+ * Forced read idle interval to be used when voltage is stable
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL			(50*1000000)
+
+/* DLL calibration interval when voltage is NOT stable - 1us */
+#define DLL_CALIB_INTERVAL_DVFS				(1*1000000)
+
+#define DLL_CALIB_ACK_WAIT_VAL				5
+
+/* Interval between ZQCS commands - hw team recommended value */
+#define EMIF_ZQCS_INTERVAL_US				(50*1000)
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define ZQ_SFEXITEN_ENABLE				1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ */
+#define	ZQ_DUALCALEN_DISABLE				0
+#define	ZQ_DUALCALEN_ENABLE				1
+
+#define T_ZQCS_DEFAULT_NS				90
+#define T_ZQCL_DEFAULT_NS				360
+#define T_ZQINIT_DEFAULT_NS				1000
+
+/* DPD_EN */
+#define DPD_DISABLE					0
+#define DPD_ENABLE					1
+
+/*
+ * Default values for the low-power entry to be used if not provided by user.
+ * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
+ * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
+ */
+#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE		2048
+#define EMIF_LP_MODE_TIMEOUT_POWER			512
+#define EMIF_LP_MODE_FREQ_THRESHOLD			400000000
+
+/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY		0x049FF000
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY	0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY	0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
+
+/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY		0x0E084200
+#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS	10000
+
+/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
+#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS		360
+
+#define EMIF_T_CSTA					3
+#define EMIF_T_PDLL_UL					128
+
+/* External PHY control registers magic values */
+#define EMIF_EXT_PHY_CTRL_1_VAL				0x04020080
+#define EMIF_EXT_PHY_CTRL_5_VAL				0x04010040
+#define EMIF_EXT_PHY_CTRL_6_VAL				0x01004010
+#define EMIF_EXT_PHY_CTRL_7_VAL				0x00001004
+#define EMIF_EXT_PHY_CTRL_8_VAL				0x04010040
+#define EMIF_EXT_PHY_CTRL_9_VAL				0x01004010
+#define EMIF_EXT_PHY_CTRL_10_VAL			0x00001004
+#define EMIF_EXT_PHY_CTRL_11_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_12_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_13_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_14_VAL			0x80080080
+#define EMIF_EXT_PHY_CTRL_15_VAL			0x00800800
+#define EMIF_EXT_PHY_CTRL_16_VAL			0x08102040
+#define EMIF_EXT_PHY_CTRL_17_VAL			0x00000001
+#define EMIF_EXT_PHY_CTRL_18_VAL			0x540A8150
+#define EMIF_EXT_PHY_CTRL_19_VAL			0xA81502A0
+#define EMIF_EXT_PHY_CTRL_20_VAL			0x002A0540
+#define EMIF_EXT_PHY_CTRL_21_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_22_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_23_VAL			0x00000000
+#define EMIF_EXT_PHY_CTRL_24_VAL			0x00000077
+
+#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS	1200
+
+/* Registers offset */
+#define EMIF_MODULE_ID_AND_REVISION			0x0000
+#define EMIF_STATUS					0x0004
+#define EMIF_SDRAM_CONFIG				0x0008
+#define EMIF_SDRAM_CONFIG_2				0x000c
+#define EMIF_SDRAM_REFRESH_CONTROL			0x0010
+#define EMIF_SDRAM_REFRESH_CTRL_SHDW			0x0014
+#define EMIF_SDRAM_TIMING_1				0x0018
+#define EMIF_SDRAM_TIMING_1_SHDW			0x001c
+#define EMIF_SDRAM_TIMING_2				0x0020
+#define EMIF_SDRAM_TIMING_2_SHDW			0x0024
+#define EMIF_SDRAM_TIMING_3				0x0028
+#define EMIF_SDRAM_TIMING_3_SHDW			0x002c
+#define EMIF_LPDDR2_NVM_TIMING				0x0030
+#define EMIF_LPDDR2_NVM_TIMING_SHDW			0x0034
+#define EMIF_POWER_MANAGEMENT_CONTROL			0x0038
+#define EMIF_POWER_MANAGEMENT_CTRL_SHDW			0x003c
+#define EMIF_LPDDR2_MODE_REG_DATA			0x0040
+#define EMIF_LPDDR2_MODE_REG_CONFIG			0x0050
+#define EMIF_OCP_CONFIG					0x0054
+#define EMIF_OCP_CONFIG_VALUE_1				0x0058
+#define EMIF_OCP_CONFIG_VALUE_2				0x005c
+#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL		0x0060
+#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT		0x0064
+#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT	0x0068
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1	0x006c
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2	0x0070
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3	0x0074
+#define EMIF_PERFORMANCE_COUNTER_1			0x0080
+#define EMIF_PERFORMANCE_COUNTER_2			0x0084
+#define EMIF_PERFORMANCE_COUNTER_CONFIG			0x0088
+#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT	0x008c
+#define EMIF_PERFORMANCE_COUNTER_TIME			0x0090
+#define EMIF_MISC_REG					0x0094
+#define EMIF_DLL_CALIB_CTRL				0x0098
+#define EMIF_DLL_CALIB_CTRL_SHDW			0x009c
+#define EMIF_END_OF_INTERRUPT				0x00a0
+#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS		0x00a4
+#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS		0x00a8
+#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS		0x00ac
+#define EMIF_LL_OCP_INTERRUPT_STATUS			0x00b0
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET		0x00b4
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET		0x00b8
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR		0x00bc
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR		0x00c0
+#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG	0x00c8
+#define EMIF_TEMPERATURE_ALERT_CONFIG			0x00cc
+#define EMIF_OCP_ERROR_LOG				0x00d0
+#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW		0x00d4
+#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL		0x00d8
+#define EMIF_READ_WRITE_LEVELING_CONTROL		0x00dc
+#define EMIF_DDR_PHY_CTRL_1				0x00e4
+#define EMIF_DDR_PHY_CTRL_1_SHDW			0x00e8
+#define EMIF_DDR_PHY_CTRL_2				0x00ec
+#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING	0x0100
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
+#define EMIF_READ_WRITE_EXECUTION_THRESHOLD		0x0120
+#define EMIF_COS_CONFIG					0x0124
+#define EMIF_PHY_STATUS_1				0x0140
+#define EMIF_PHY_STATUS_2				0x0144
+#define EMIF_PHY_STATUS_3				0x0148
+#define EMIF_PHY_STATUS_4				0x014c
+#define EMIF_PHY_STATUS_5				0x0150
+#define EMIF_PHY_STATUS_6				0x0154
+#define EMIF_PHY_STATUS_7				0x0158
+#define EMIF_PHY_STATUS_8				0x015c
+#define EMIF_PHY_STATUS_9				0x0160
+#define EMIF_PHY_STATUS_10				0x0164
+#define EMIF_PHY_STATUS_11				0x0168
+#define EMIF_PHY_STATUS_12				0x016c
+#define EMIF_PHY_STATUS_13				0x0170
+#define EMIF_PHY_STATUS_14				0x0174
+#define EMIF_PHY_STATUS_15				0x0178
+#define EMIF_PHY_STATUS_16				0x017c
+#define EMIF_PHY_STATUS_17				0x0180
+#define EMIF_PHY_STATUS_18				0x0184
+#define EMIF_PHY_STATUS_19				0x0188
+#define EMIF_PHY_STATUS_20				0x018c
+#define EMIF_PHY_STATUS_21				0x0190
+#define EMIF_EXT_PHY_CTRL_1				0x0200
+#define EMIF_EXT_PHY_CTRL_1_SHDW			0x0204
+#define EMIF_EXT_PHY_CTRL_2				0x0208
+#define EMIF_EXT_PHY_CTRL_2_SHDW			0x020c
+#define EMIF_EXT_PHY_CTRL_3				0x0210
+#define EMIF_EXT_PHY_CTRL_3_SHDW			0x0214
+#define EMIF_EXT_PHY_CTRL_4				0x0218
+#define EMIF_EXT_PHY_CTRL_4_SHDW			0x021c
+#define EMIF_EXT_PHY_CTRL_5				0x0220
+#define EMIF_EXT_PHY_CTRL_5_SHDW			0x0224
+#define EMIF_EXT_PHY_CTRL_6				0x0228
+#define EMIF_EXT_PHY_CTRL_6_SHDW			0x022c
+#define EMIF_EXT_PHY_CTRL_7				0x0230
+#define EMIF_EXT_PHY_CTRL_7_SHDW			0x0234
+#define EMIF_EXT_PHY_CTRL_8				0x0238
+#define EMIF_EXT_PHY_CTRL_8_SHDW			0x023c
+#define EMIF_EXT_PHY_CTRL_9				0x0240
+#define EMIF_EXT_PHY_CTRL_9_SHDW			0x0244
+#define EMIF_EXT_PHY_CTRL_10				0x0248
+#define EMIF_EXT_PHY_CTRL_10_SHDW			0x024c
+#define EMIF_EXT_PHY_CTRL_11				0x0250
+#define EMIF_EXT_PHY_CTRL_11_SHDW			0x0254
+#define EMIF_EXT_PHY_CTRL_12				0x0258
+#define EMIF_EXT_PHY_CTRL_12_SHDW			0x025c
+#define EMIF_EXT_PHY_CTRL_13				0x0260
+#define EMIF_EXT_PHY_CTRL_13_SHDW			0x0264
+#define EMIF_EXT_PHY_CTRL_14				0x0268
+#define EMIF_EXT_PHY_CTRL_14_SHDW			0x026c
+#define EMIF_EXT_PHY_CTRL_15				0x0270
+#define EMIF_EXT_PHY_CTRL_15_SHDW			0x0274
+#define EMIF_EXT_PHY_CTRL_16				0x0278
+#define EMIF_EXT_PHY_CTRL_16_SHDW			0x027c
+#define EMIF_EXT_PHY_CTRL_17				0x0280
+#define EMIF_EXT_PHY_CTRL_17_SHDW			0x0284
+#define EMIF_EXT_PHY_CTRL_18				0x0288
+#define EMIF_EXT_PHY_CTRL_18_SHDW			0x028c
+#define EMIF_EXT_PHY_CTRL_19				0x0290
+#define EMIF_EXT_PHY_CTRL_19_SHDW			0x0294
+#define EMIF_EXT_PHY_CTRL_20				0x0298
+#define EMIF_EXT_PHY_CTRL_20_SHDW			0x029c
+#define EMIF_EXT_PHY_CTRL_21				0x02a0
+#define EMIF_EXT_PHY_CTRL_21_SHDW			0x02a4
+#define EMIF_EXT_PHY_CTRL_22				0x02a8
+#define EMIF_EXT_PHY_CTRL_22_SHDW			0x02ac
+#define EMIF_EXT_PHY_CTRL_23				0x02b0
+#define EMIF_EXT_PHY_CTRL_23_SHDW			0x02b4
+#define EMIF_EXT_PHY_CTRL_24				0x02b8
+#define EMIF_EXT_PHY_CTRL_24_SHDW			0x02bc
+#define EMIF_EXT_PHY_CTRL_25				0x02c0
+#define EMIF_EXT_PHY_CTRL_25_SHDW			0x02c4
+#define EMIF_EXT_PHY_CTRL_26				0x02c8
+#define EMIF_EXT_PHY_CTRL_26_SHDW			0x02cc
+#define EMIF_EXT_PHY_CTRL_27				0x02d0
+#define EMIF_EXT_PHY_CTRL_27_SHDW			0x02d4
+#define EMIF_EXT_PHY_CTRL_28				0x02d8
+#define EMIF_EXT_PHY_CTRL_28_SHDW			0x02dc
+#define EMIF_EXT_PHY_CTRL_29				0x02e0
+#define EMIF_EXT_PHY_CTRL_29_SHDW			0x02e4
+#define EMIF_EXT_PHY_CTRL_30				0x02e8
+#define EMIF_EXT_PHY_CTRL_30_SHDW			0x02ec
+
+/* Registers shifts and masks */
+
+/* EMIF_MODULE_ID_AND_REVISION */
+#define SCHEME_SHIFT					30
+#define SCHEME_MASK					(0x3 << 30)
+#define MODULE_ID_SHIFT					16
+#define MODULE_ID_MASK					(0xfff << 16)
+#define RTL_VERSION_SHIFT				11
+#define RTL_VERSION_MASK				(0x1f << 11)
+#define MAJOR_REVISION_SHIFT				8
+#define MAJOR_REVISION_MASK				(0x7 << 8)
+#define MINOR_REVISION_SHIFT				0
+#define MINOR_REVISION_MASK				(0x3f << 0)
+
+/* STATUS */
+#define BE_SHIFT					31
+#define BE_MASK						(1 << 31)
+#define DUAL_CLK_MODE_SHIFT				30
+#define DUAL_CLK_MODE_MASK				(1 << 30)
+#define FAST_INIT_SHIFT					29
+#define FAST_INIT_MASK					(1 << 29)
+#define RDLVLGATETO_SHIFT				6
+#define RDLVLGATETO_MASK				(1 << 6)
+#define RDLVLTO_SHIFT					5
+#define RDLVLTO_MASK					(1 << 5)
+#define WRLVLTO_SHIFT					4
+#define WRLVLTO_MASK					(1 << 4)
+#define PHY_DLL_READY_SHIFT				2
+#define PHY_DLL_READY_MASK				(1 << 2)
+
+/* SDRAM_CONFIG */
+#define SDRAM_TYPE_SHIFT				29
+#define SDRAM_TYPE_MASK					(0x7 << 29)
+#define IBANK_POS_SHIFT					27
+#define IBANK_POS_MASK					(0x3 << 27)
+#define DDR_TERM_SHIFT					24
+#define DDR_TERM_MASK					(0x7 << 24)
+#define DDR2_DDQS_SHIFT					23
+#define DDR2_DDQS_MASK					(1 << 23)
+#define DYN_ODT_SHIFT					21
+#define DYN_ODT_MASK					(0x3 << 21)
+#define DDR_DISABLE_DLL_SHIFT				20
+#define DDR_DISABLE_DLL_MASK				(1 << 20)
+#define SDRAM_DRIVE_SHIFT				18
+#define SDRAM_DRIVE_MASK				(0x3 << 18)
+#define CWL_SHIFT					16
+#define CWL_MASK					(0x3 << 16)
+#define NARROW_MODE_SHIFT				14
+#define NARROW_MODE_MASK				(0x3 << 14)
+#define CL_SHIFT					10
+#define CL_MASK						(0xf << 10)
+#define ROWSIZE_SHIFT					7
+#define ROWSIZE_MASK					(0x7 << 7)
+#define IBANK_SHIFT					4
+#define IBANK_MASK					(0x7 << 4)
+#define EBANK_SHIFT					3
+#define EBANK_MASK					(1 << 3)
+#define PAGESIZE_SHIFT					0
+#define PAGESIZE_MASK					(0x7 << 0)
+
+/* SDRAM_CONFIG_2 */
+#define CS1NVMEN_SHIFT					30
+#define CS1NVMEN_MASK					(1 << 30)
+#define EBANK_POS_SHIFT					27
+#define EBANK_POS_MASK					(1 << 27)
+#define RDBNUM_SHIFT					4
+#define RDBNUM_MASK					(0x3 << 4)
+#define RDBSIZE_SHIFT					0
+#define RDBSIZE_MASK					(0x7 << 0)
+
+/* SDRAM_REFRESH_CONTROL */
+#define INITREF_DIS_SHIFT				31
+#define INITREF_DIS_MASK				(1 << 31)
+#define SRT_SHIFT					29
+#define SRT_MASK					(1 << 29)
+#define ASR_SHIFT					28
+#define ASR_MASK					(1 << 28)
+#define PASR_SHIFT					24
+#define PASR_MASK					(0x7 << 24)
+#define REFRESH_RATE_SHIFT				0
+#define REFRESH_RATE_MASK				(0xffff << 0)
+
+/* SDRAM_TIMING_1 */
+#define T_RTW_SHIFT					29
+#define T_RTW_MASK					(0x7 << 29)
+#define T_RP_SHIFT					25
+#define T_RP_MASK					(0xf << 25)
+#define T_RCD_SHIFT					21
+#define T_RCD_MASK					(0xf << 21)
+#define T_WR_SHIFT					17
+#define T_WR_MASK					(0xf << 17)
+#define T_RAS_SHIFT					12
+#define T_RAS_MASK					(0x1f << 12)
+#define T_RC_SHIFT					6
+#define T_RC_MASK					(0x3f << 6)
+#define T_RRD_SHIFT					3
+#define T_RRD_MASK					(0x7 << 3)
+#define T_WTR_SHIFT					0
+#define T_WTR_MASK					(0x7 << 0)
+
+/* SDRAM_TIMING_2 */
+#define T_XP_SHIFT					28
+#define T_XP_MASK					(0x7 << 28)
+#define T_ODT_SHIFT					25
+#define T_ODT_MASK					(0x7 << 25)
+#define T_XSNR_SHIFT					16
+#define T_XSNR_MASK					(0x1ff << 16)
+#define T_XSRD_SHIFT					6
+#define T_XSRD_MASK					(0x3ff << 6)
+#define T_RTP_SHIFT					3
+#define T_RTP_MASK					(0x7 << 3)
+#define T_CKE_SHIFT					0
+#define T_CKE_MASK					(0x7 << 0)
+
+/* SDRAM_TIMING_3 */
+#define T_PDLL_UL_SHIFT					28
+#define T_PDLL_UL_MASK					(0xf << 28)
+#define T_CSTA_SHIFT					24
+#define T_CSTA_MASK					(0xf << 24)
+#define T_CKESR_SHIFT					21
+#define T_CKESR_MASK					(0x7 << 21)
+#define ZQ_ZQCS_SHIFT					15
+#define ZQ_ZQCS_MASK					(0x3f << 15)
+#define T_TDQSCKMAX_SHIFT				13
+#define T_TDQSCKMAX_MASK				(0x3 << 13)
+#define T_RFC_SHIFT					4
+#define T_RFC_MASK					(0x1ff << 4)
+#define T_RAS_MAX_SHIFT					0
+#define T_RAS_MAX_MASK					(0xf << 0)
+
+/* POWER_MANAGEMENT_CONTROL */
+#define PD_TIM_SHIFT					12
+#define PD_TIM_MASK					(0xf << 12)
+#define DPD_EN_SHIFT					11
+#define DPD_EN_MASK					(1 << 11)
+#define LP_MODE_SHIFT					8
+#define LP_MODE_MASK					(0x7 << 8)
+#define SR_TIM_SHIFT					4
+#define SR_TIM_MASK					(0xf << 4)
+#define CS_TIM_SHIFT					0
+#define CS_TIM_MASK					(0xf << 0)
+
+/* LPDDR2_MODE_REG_DATA */
+#define VALUE_0_SHIFT					0
+#define VALUE_0_MASK					(0x7f << 0)
+
+/* LPDDR2_MODE_REG_CONFIG */
+#define CS_SHIFT					31
+#define CS_MASK						(1 << 31)
+#define REFRESH_EN_SHIFT				30
+#define REFRESH_EN_MASK					(1 << 30)
+#define ADDRESS_SHIFT					0
+#define ADDRESS_MASK					(0xff << 0)
+
+/* OCP_CONFIG */
+#define SYS_THRESH_MAX_SHIFT				24
+#define SYS_THRESH_MAX_MASK				(0xf << 24)
+#define MPU_THRESH_MAX_SHIFT				20
+#define MPU_THRESH_MAX_MASK				(0xf << 20)
+#define LL_THRESH_MAX_SHIFT				16
+#define LL_THRESH_MAX_MASK				(0xf << 16)
+
+/* PERFORMANCE_COUNTER_1 */
+#define COUNTER1_SHIFT					0
+#define COUNTER1_MASK					(0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_2 */
+#define COUNTER2_SHIFT					0
+#define COUNTER2_MASK					(0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_CONFIG */
+#define CNTR2_MCONNID_EN_SHIFT				31
+#define CNTR2_MCONNID_EN_MASK				(1 << 31)
+#define CNTR2_REGION_EN_SHIFT				30
+#define CNTR2_REGION_EN_MASK				(1 << 30)
+#define CNTR2_CFG_SHIFT					16
+#define CNTR2_CFG_MASK					(0xf << 16)
+#define CNTR1_MCONNID_EN_SHIFT				15
+#define CNTR1_MCONNID_EN_MASK				(1 << 15)
+#define CNTR1_REGION_EN_SHIFT				14
+#define CNTR1_REGION_EN_MASK				(1 << 14)
+#define CNTR1_CFG_SHIFT					0
+#define CNTR1_CFG_MASK					(0xf << 0)
+
+/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
+#define MCONNID2_SHIFT					24
+#define MCONNID2_MASK					(0xff << 24)
+#define REGION_SEL2_SHIFT				16
+#define REGION_SEL2_MASK				(0x3 << 16)
+#define MCONNID1_SHIFT					8
+#define MCONNID1_MASK					(0xff << 8)
+#define REGION_SEL1_SHIFT				0
+#define REGION_SEL1_MASK				(0x3 << 0)
+
+/* PERFORMANCE_COUNTER_TIME */
+#define TOTAL_TIME_SHIFT				0
+#define TOTAL_TIME_MASK					(0xffffffff << 0)
+
+/* DLL_CALIB_CTRL */
+#define ACK_WAIT_SHIFT					16
+#define ACK_WAIT_MASK					(0xf << 16)
+#define DLL_CALIB_INTERVAL_SHIFT			0
+#define DLL_CALIB_INTERVAL_MASK				(0x1ff << 0)
+
+/* END_OF_INTERRUPT */
+#define EOI_SHIFT					0
+#define EOI_MASK					(1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_SYS_SHIFT					2
+#define DNV_SYS_MASK					(1 << 2)
+#define TA_SYS_SHIFT					1
+#define TA_SYS_MASK					(1 << 1)
+#define ERR_SYS_SHIFT					0
+#define ERR_SYS_MASK					(1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_LL_SHIFT					2
+#define DNV_LL_MASK					(1 << 2)
+#define TA_LL_SHIFT					1
+#define TA_LL_MASK					(1 << 1)
+#define ERR_LL_SHIFT					0
+#define ERR_LL_MASK					(1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_SYS_SHIFT				2
+#define EN_DNV_SYS_MASK					(1 << 2)
+#define EN_TA_SYS_SHIFT					1
+#define EN_TA_SYS_MASK					(1 << 1)
+#define EN_ERR_SYS_SHIFT					0
+#define EN_ERR_SYS_MASK					(1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_LL_SHIFT					2
+#define EN_DNV_LL_MASK					(1 << 2)
+#define EN_TA_LL_SHIFT					1
+#define EN_TA_LL_MASK					(1 << 1)
+#define EN_ERR_LL_SHIFT					0
+#define EN_ERR_LL_MASK					(1 << 0)
+
+/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
+#define ZQ_CS1EN_SHIFT					31
+#define ZQ_CS1EN_MASK					(1 << 31)
+#define ZQ_CS0EN_SHIFT					30
+#define ZQ_CS0EN_MASK					(1 << 30)
+#define ZQ_DUALCALEN_SHIFT				29
+#define ZQ_DUALCALEN_MASK				(1 << 29)
+#define ZQ_SFEXITEN_SHIFT				28
+#define ZQ_SFEXITEN_MASK				(1 << 28)
+#define ZQ_ZQINIT_MULT_SHIFT				18
+#define ZQ_ZQINIT_MULT_MASK				(0x3 << 18)
+#define ZQ_ZQCL_MULT_SHIFT				16
+#define ZQ_ZQCL_MULT_MASK				(0x3 << 16)
+#define ZQ_REFINTERVAL_SHIFT				0
+#define ZQ_REFINTERVAL_MASK				(0xffff << 0)
+
+/* TEMPERATURE_ALERT_CONFIG */
+#define TA_CS1EN_SHIFT					31
+#define TA_CS1EN_MASK					(1 << 31)
+#define TA_CS0EN_SHIFT					30
+#define TA_CS0EN_MASK					(1 << 30)
+#define TA_SFEXITEN_SHIFT				28
+#define TA_SFEXITEN_MASK				(1 << 28)
+#define TA_DEVWDT_SHIFT					26
+#define TA_DEVWDT_MASK					(0x3 << 26)
+#define TA_DEVCNT_SHIFT					24
+#define TA_DEVCNT_MASK					(0x3 << 24)
+#define TA_REFINTERVAL_SHIFT				0
+#define TA_REFINTERVAL_MASK				(0x3fffff << 0)
+
+/* OCP_ERROR_LOG */
+#define MADDRSPACE_SHIFT				14
+#define MADDRSPACE_MASK					(0x3 << 14)
+#define MBURSTSEQ_SHIFT					11
+#define MBURSTSEQ_MASK					(0x7 << 11)
+#define MCMD_SHIFT					8
+#define MCMD_MASK					(0x7 << 8)
+#define MCONNID_SHIFT					0
+#define MCONNID_MASK					(0xff << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D */
+#define DLL_SLAVE_DLY_CTRL_SHIFT_4D			4
+#define DLL_SLAVE_DLY_CTRL_MASK_4D			(0xFF << 4)
+#define READ_LATENCY_SHIFT_4D				0
+#define READ_LATENCY_MASK_4D				(0xf << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D5 */
+#define DLL_HALF_DELAY_SHIFT_4D5			21
+#define DLL_HALF_DELAY_MASK_4D5				(1 << 21)
+#define READ_LATENCY_SHIFT_4D5				0
+#define READ_LATENCY_MASK_4D5				(0x1f << 0)
+
+/* DDR_PHY_CTRL_1_SHDW */
+#define DDR_PHY_CTRL_1_SHDW_SHIFT			5
+#define DDR_PHY_CTRL_1_SHDW_MASK			(0x7ffffff << 5)
+#define READ_LATENCY_SHDW_SHIFT				0
+#define READ_LATENCY_SHDW_MASK				(0x1f << 0)
+
+#endif /* __TI_EMIF_H */
#4 lore raw

PATCH v3 1/9 memory: emif: Move EMIF register defines to include/linux/

Quoted 28 lines · Santosh Shilimkar

(You have not CC'ed Greg, Looping him)

Quoted 15 lines · Dave Gerlach

OMAP4 and AM33XX share the same EMIF controller IP. Although there are significant differences in the IP integration due to which AM33XX can't reuse the EMIF driver DVFS similar to OMAP4, it can definitely benefit by reusing the EMIF related macros defined in drivers/memory/emif.h.

In the current OMAP PM framework the PM code resides under arch/arm/mach-omap2/. To enable reuse of the register defines move the register defines in the emif header file to include/linux so that both the EMIF driver and the AM33XX PM code can benefit.

Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Aneesh V <[email protected]>
Quoted 6 lines
---
 drivers/memory/emif.h   |  543 +--------------------------------------------
 include/linux/ti_emif.h |  558 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 559 insertions(+), 542 deletions(-)
 create mode 100644 include/linux/ti_emif.h

For file movement or some part of file movement, while formating patch, use "git format-patch -C" so that only delta change will appear in the patch.

Quoted 7 lines

The patch as such is fine by me.

Greg,
Your ack is needed on this patch so that it can go along with the series. Subsequent patch from this series use the register defines from this patch.

#5 lore raw

PATCH v3 1/9 memory: emif: Move EMIF register defines to include/linux/

Quoted 32 lines · Greg Kroah-Hartman
Quoted 31 lines · Santosh Shilimkar

(You have not CC'ed Greg, Looping him)

Quoted 15 lines · Dave Gerlach

OMAP4 and AM33XX share the same EMIF controller IP. Although there are significant differences in the IP integration due to which AM33XX can't reuse the EMIF driver DVFS similar to OMAP4, it can definitely benefit by reusing the EMIF related macros defined in drivers/memory/emif.h.

In the current OMAP PM framework the PM code resides under arch/arm/mach-omap2/. To enable reuse of the register defines move the register defines in the emif header file to include/linux so that both the EMIF driver and the AM33XX PM code can benefit.

Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Aneesh V <[email protected]>
Quoted 6 lines
---
 drivers/memory/emif.h   |  543 +--------------------------------------------
 include/linux/ti_emif.h |  558 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 559 insertions(+), 542 deletions(-)
 create mode 100644 include/linux/ti_emif.h

For file movement or some part of file movement, while formating patch, use "git format-patch -C" so that only delta change will appear in the patch.

The patch as such is fine by me.

Quoted 7 lines
Quoted 4 lines

Greg,
Your ack is needed on this patch so that it can go along with the series. Subsequent patch from this series use the register defines from this patch.

Thanks !!

#6 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Interacting with WKUP-M3 requires some more control module register writes. Add the register offsets and APIs to write to these.

---
 arch/arm/mach-omap2/control.c |   57 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/control.h |   54 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
arch/arm/mach-omap2/control.c +57 -0
index 31e0dfe..934041a 100644
@@ -605,3 +605,60 @@ int omap3_ctrl_save_padconf(void)
 }
 
 #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
+
+#if defined(CONFIG_SOC_AM33XX) && defined(CONFIG_PM)
+void am33xx_txev_eoi(void)
+{
+	omap_ctrl_writel(AM33XX_M3_TXEV_ACK, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+void am33xx_txev_enable(void)
+{
+	omap_ctrl_writel(AM33XX_M3_TXEV_ENABLE, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+/*
+ * Invalidate M3 firmware version before hardreset.
+ * Write invalid version in lower 4 nibbles of parameter
+ * register (ipc_regs + 0x8).
+ */
+void am33xx_pm_version_clear(void)
+{
+	omap_ctrl_writel(0xffff0000, AM33XX_CONTROL_IPC_MSG_REG2);
+}
+
+int am33xx_pm_version_get(void)
+{
+	return omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG2) & M3_VERSION_MASK;
+}
+
+void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
+{
+	omap_ctrl_writel(data->resume_addr, AM33XX_CONTROL_IPC_MSG_REG0);
+	omap_ctrl_writel(data->sleep_mode, AM33XX_CONTROL_IPC_MSG_REG1);
+	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
+	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
+	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
+}
+
+int am33xx_pm_status(void)
+{
+	int i;
+
+	i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG1);
+	i &= IPC_RESP_MASK;
+	i >>= __ffs(IPC_RESP_MASK);
+
+	return i;
+}
+
+int am33xx_pm_wake_src(void)
+{
+	int i;
+
+	i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG6);
+	i &= 0xff;
+
+	return i;
+}
+#endif /* CONFIG_SOC_AM33XX && CONFIG_PM */
arch/arm/mach-omap2/control.h +54 -0

66 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#7 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 8 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Interacting with WKUP-M3 requires some more control module register writes. Add the register offsets and APIs to write to these.

Quoted 150 lines
---
 arch/arm/mach-omap2/control.c |   57 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/control.h |   54 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
arch/arm/mach-omap2/control.c +57 -0
index 31e0dfe..934041a 100644
@@ -605,3 +605,60 @@ int omap3_ctrl_save_padconf(void)
 }
 
 #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
+
+#if defined(CONFIG_SOC_AM33XX) && defined(CONFIG_PM)
+void am33xx_txev_eoi(void)
+{
+       omap_ctrl_writel(AM33XX_M3_TXEV_ACK, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+void am33xx_txev_enable(void)
+{
+       omap_ctrl_writel(AM33XX_M3_TXEV_ENABLE, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+/*
+ * Invalidate M3 firmware version before hardreset.
+ * Write invalid version in lower 4 nibbles of parameter
+ * register (ipc_regs + 0x8).
+ */
+void am33xx_pm_version_clear(void)
+{
+       omap_ctrl_writel(0xffff0000, AM33XX_CONTROL_IPC_MSG_REG2);
+}
+
+int am33xx_pm_version_get(void)
+{
+       return omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG2) & M3_VERSION_MASK;
+}
+
+void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
+{
+       omap_ctrl_writel(data->resume_addr, AM33XX_CONTROL_IPC_MSG_REG0);
+       omap_ctrl_writel(data->sleep_mode, AM33XX_CONTROL_IPC_MSG_REG1);
+       omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
+       omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
+       omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
+}
+
+int am33xx_pm_status(void)
+{
+       int i;
+
+       i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG1);
+       i &= IPC_RESP_MASK;
+       i >>= __ffs(IPC_RESP_MASK);
+
+       return i;
+}
+
+int am33xx_pm_wake_src(void)
+{
+       int i;
+
+       i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG6);
+       i &= 0xff;
+
+       return i;
+}
+#endif /* CONFIG_SOC_AM33XX && CONFIG_PM */
arch/arm/mach-omap2/control.h +54 -1
index f7d7c2e..9be587c 100644
@@ -370,6 +370,22 @@
 #define AM33XX_DEV_FEATURE             0x604
 #define AM33XX_SGX_MASK                        BIT(29)
 
+/* AM33XX M3_TXEV_EOI register */
+#define AM33XX_CONTROL_M3_TXEV_EOI     0x1324
+
+#define AM33XX_M3_TXEV_ACK             (0x1 << 0)
+#define AM33XX_M3_TXEV_ENABLE          (0x0 << 0)
+
+/* AM33XX IPC message registers */
+#define AM33XX_CONTROL_IPC_MSG_REG0    0x1328
+#define AM33XX_CONTROL_IPC_MSG_REG1    0x132C
+#define AM33XX_CONTROL_IPC_MSG_REG2    0x1330
+#define AM33XX_CONTROL_IPC_MSG_REG3    0x1334
+#define AM33XX_CONTROL_IPC_MSG_REG4    0x1338
+#define AM33XX_CONTROL_IPC_MSG_REG5    0x133C
+#define AM33XX_CONTROL_IPC_MSG_REG6    0x1340
+#define AM33XX_CONTROL_IPC_MSG_REG7    0x1344
+
 /* CONTROL OMAP STATUS register to identify OMAP3 features */
 #define OMAP3_CONTROL_OMAP_STATUS      0x044c
 
@@ -429,6 +445,44 @@ extern void omap3630_ctrl_disable_rta(void);
 extern int omap3_ctrl_save_padconf(void);
 extern void omap2_set_globals_control(void __iomem *ctrl,
                                      void __iomem *ctrl_pad);
+struct am33xx_ipc_data {
+       u32 resume_addr;
+       u32 sleep_mode;
+       u32 param1;
+       u32 param2;
+       u32 param3;
+       u32 param4;
+       u32 param5;
+       u32 param6;
+};
+
+#define IPC_RESP_SHIFT                 16
+#define IPC_RESP_MASK                  (0xffff << 16)
+
+#define M3_VERSION_SHIFT               0
+#define M3_VERSION_MASK                        (0xffff << 0)
+
+/*
+ * 9-4 = VTT GPIO PIN (6 Bits)
+ *   3 = VTT Status (1 Bit)
+ * 2-0 = Memory Type (2 Bits)
+*/
+#define MEM_TYPE_SHIFT         (0x0)
+#define MEM_TYPE_MASK          (0x7 << 0)
+#define VTT_STAT_SHIFT         (0x3)
+#define VTT_STAT_MASK          (0x1 << 3)
+#define VTT_GPIO_PIN_SHIFT     (0x4)
+#define VTT_GPIO_PIN_MASK      (0x2f << 4)
+
+extern void am33xx_wkup_m3_ipc_cmd(struct am33xx_ipc_data *data);
+extern void am33xx_txev_eoi(void);
+extern void am33xx_txev_enable(void);
+extern void am33xx_pm_version_clear(void);
+extern int am33xx_pm_version_get(void);
+extern void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data);
+extern int am33xx_pm_status(void);
+extern int am33xx_pm_wake_src(void);
+
 #else
 #define omap_ctrl_base_get()           0
 #define omap_ctrl_readb(x)             0
--

1.7.9.5

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#8 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

In reply to Dave Gerlach
Quoted 137 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Interacting with WKUP-M3 requires some more control module register writes. Add the register offsets and APIs to write to these.

---
 arch/arm/mach-omap2/control.c |   57 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/control.h |   54 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+)
arch/arm/mach-omap2/control.c +57 -0
index 31e0dfe..934041a 100644
@@ -605,3 +605,60 @@ int omap3_ctrl_save_padconf(void)
 }
 
 #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
+
+#if defined(CONFIG_SOC_AM33XX) && defined(CONFIG_PM)
+void am33xx_txev_eoi(void)
+{
+	omap_ctrl_writel(AM33XX_M3_TXEV_ACK, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+void am33xx_txev_enable(void)
+{
+	omap_ctrl_writel(AM33XX_M3_TXEV_ENABLE, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+/*
+ * Invalidate M3 firmware version before hardreset.
+ * Write invalid version in lower 4 nibbles of parameter
+ * register (ipc_regs + 0x8).
+ */
+void am33xx_pm_version_clear(void)
+{
+	omap_ctrl_writel(0xffff0000, AM33XX_CONTROL_IPC_MSG_REG2);
+}
+
+int am33xx_pm_version_get(void)
+{
+	return omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG2) & M3_VERSION_MASK;
+}
+
+void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
+{
+	omap_ctrl_writel(data->resume_addr, AM33XX_CONTROL_IPC_MSG_REG0);
+	omap_ctrl_writel(data->sleep_mode, AM33XX_CONTROL_IPC_MSG_REG1);
+	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
+	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
+	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
+}
+
+int am33xx_pm_status(void)
+{
+	int i;
+
+	i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG1);
+	i &= IPC_RESP_MASK;
+	i >>= __ffs(IPC_RESP_MASK);
+
+	return i;
+}
+
+int am33xx_pm_wake_src(void)
+{
+	int i;
+
+	i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG6);
+	i &= 0xff;
+
+	return i;
+}
+#endif /* CONFIG_SOC_AM33XX && CONFIG_PM */
arch/arm/mach-omap2/control.h +44 -0
index f7d7c2e..9be587c 100644
@@ -370,6 +370,22 @@
 #define AM33XX_DEV_FEATURE		0x604
 #define AM33XX_SGX_MASK			BIT(29)
 
+/* AM33XX M3_TXEV_EOI register */
+#define AM33XX_CONTROL_M3_TXEV_EOI	0x1324
+
+#define AM33XX_M3_TXEV_ACK		(0x1 << 0)
+#define AM33XX_M3_TXEV_ENABLE		(0x0 << 0)
+
+/* AM33XX IPC message registers */
+#define AM33XX_CONTROL_IPC_MSG_REG0	0x1328
+#define AM33XX_CONTROL_IPC_MSG_REG1	0x132C
+#define AM33XX_CONTROL_IPC_MSG_REG2	0x1330
+#define AM33XX_CONTROL_IPC_MSG_REG3	0x1334
+#define AM33XX_CONTROL_IPC_MSG_REG4	0x1338
+#define AM33XX_CONTROL_IPC_MSG_REG5	0x133C
+#define AM33XX_CONTROL_IPC_MSG_REG6	0x1340
+#define AM33XX_CONTROL_IPC_MSG_REG7	0x1344
+
 /* CONTROL OMAP STATUS register to identify OMAP3 features */
 #define OMAP3_CONTROL_OMAP_STATUS	0x044c
 
@@ -429,6 +445,44 @@ extern void omap3630_ctrl_disable_rta(void);
 extern int omap3_ctrl_save_padconf(void);
 extern void omap2_set_globals_control(void __iomem *ctrl,
 				      void __iomem *ctrl_pad);
+struct am33xx_ipc_data {
+	u32 resume_addr;
+	u32 sleep_mode;
+	u32 param1;
+	u32 param2;
+	u32 param3;
+	u32 param4;
+	u32 param5;
+	u32 param6;
+};
+
+#define IPC_RESP_SHIFT			16
+#define IPC_RESP_MASK			(0xffff << 16)
+
+#define M3_VERSION_SHIFT		0
+#define M3_VERSION_MASK			(0xffff << 0)
+
+/*
+ * 9-4 = VTT GPIO PIN (6 Bits)
+ *   3 = VTT Status (1 Bit)
+ * 2-0 = Memory Type (2 Bits)
+*/
+#define MEM_TYPE_SHIFT		(0x0)
+#define MEM_TYPE_MASK		(0x7 << 0)
+#define VTT_STAT_SHIFT		(0x3)
+#define VTT_STAT_MASK		(0x1 << 3)
+#define VTT_GPIO_PIN_SHIFT	(0x4)
+#define VTT_GPIO_PIN_MASK	(0x2f << 4)

arch/arm/mach-omap2/control.h extern void omap3630_ctrl_disable_rta(void); · line 485

Quoted 10 lines
arch/arm/mach-omap2/control.h +10 -0
+
+extern void am33xx_wkup_m3_ipc_cmd(struct am33xx_ipc_data *data);
+extern void am33xx_txev_eoi(void);
+extern void am33xx_txev_enable(void);
+extern void am33xx_pm_version_clear(void);
+extern int am33xx_pm_version_get(void);
+extern void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data);
+extern int am33xx_pm_status(void);
+extern int am33xx_pm_wake_src(void);
+

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

Regards,
Santosh

#9 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 151 lines · Santosh Shilimkar
Quoted 137 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Interacting with WKUP-M3 requires some more control module register writes. Add the register offsets and APIs to write to these.

---
  arch/arm/mach-omap2/control.c |   57 +++++++++++++++++++++++++++++++++++++++++
  arch/arm/mach-omap2/control.h |   54 ++++++++++++++++++++++++++++++++++++++
  2 files changed, 111 insertions(+)
arch/arm/mach-omap2/control.c +57 -0
index 31e0dfe..934041a 100644
@@ -605,3 +605,60 @@ int omap3_ctrl_save_padconf(void)
  }
 
  #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
+
+#if defined(CONFIG_SOC_AM33XX) && defined(CONFIG_PM)
+void am33xx_txev_eoi(void)
+{
+	omap_ctrl_writel(AM33XX_M3_TXEV_ACK, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+void am33xx_txev_enable(void)
+{
+	omap_ctrl_writel(AM33XX_M3_TXEV_ENABLE, AM33XX_CONTROL_M3_TXEV_EOI);
+}
+
+/*
+ * Invalidate M3 firmware version before hardreset.
+ * Write invalid version in lower 4 nibbles of parameter
+ * register (ipc_regs + 0x8).
+ */
+void am33xx_pm_version_clear(void)
+{
+	omap_ctrl_writel(0xffff0000, AM33XX_CONTROL_IPC_MSG_REG2);
+}
+
+int am33xx_pm_version_get(void)
+{
+	return omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG2) & M3_VERSION_MASK;
+}
+
+void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data)
+{
+	omap_ctrl_writel(data->resume_addr, AM33XX_CONTROL_IPC_MSG_REG0);
+	omap_ctrl_writel(data->sleep_mode, AM33XX_CONTROL_IPC_MSG_REG1);
+	omap_ctrl_writel(data->param1, AM33XX_CONTROL_IPC_MSG_REG2);
+	omap_ctrl_writel(data->param2, AM33XX_CONTROL_IPC_MSG_REG3);
+	omap_ctrl_writel(data->param3, AM33XX_CONTROL_IPC_MSG_REG4);
+}
+
+int am33xx_pm_status(void)
+{
+	int i;
+
+	i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG1);
+	i &= IPC_RESP_MASK;
+	i >>= __ffs(IPC_RESP_MASK);
+
+	return i;
+}
+
+int am33xx_pm_wake_src(void)
+{
+	int i;
+
+	i = omap_ctrl_readl(AM33XX_CONTROL_IPC_MSG_REG6);
+	i &= 0xff;
+
+	return i;
+}
+#endif /* CONFIG_SOC_AM33XX && CONFIG_PM */
arch/arm/mach-omap2/control.h +44 -0
index f7d7c2e..9be587c 100644
@@ -370,6 +370,22 @@
  #define AM33XX_DEV_FEATURE		0x604
  #define AM33XX_SGX_MASK			BIT(29)
 
+/* AM33XX M3_TXEV_EOI register */
+#define AM33XX_CONTROL_M3_TXEV_EOI	0x1324
+
+#define AM33XX_M3_TXEV_ACK		(0x1 << 0)
+#define AM33XX_M3_TXEV_ENABLE		(0x0 << 0)
+
+/* AM33XX IPC message registers */
+#define AM33XX_CONTROL_IPC_MSG_REG0	0x1328
+#define AM33XX_CONTROL_IPC_MSG_REG1	0x132C
+#define AM33XX_CONTROL_IPC_MSG_REG2	0x1330
+#define AM33XX_CONTROL_IPC_MSG_REG3	0x1334
+#define AM33XX_CONTROL_IPC_MSG_REG4	0x1338
+#define AM33XX_CONTROL_IPC_MSG_REG5	0x133C
+#define AM33XX_CONTROL_IPC_MSG_REG6	0x1340
+#define AM33XX_CONTROL_IPC_MSG_REG7	0x1344
+
  /* CONTROL OMAP STATUS register to identify OMAP3 features */
  #define OMAP3_CONTROL_OMAP_STATUS	0x044c
 
@@ -429,6 +445,44 @@ extern void omap3630_ctrl_disable_rta(void);
  extern int omap3_ctrl_save_padconf(void);
  extern void omap2_set_globals_control(void __iomem *ctrl,
  				      void __iomem *ctrl_pad);
+struct am33xx_ipc_data {
+	u32 resume_addr;
+	u32 sleep_mode;
+	u32 param1;
+	u32 param2;
+	u32 param3;
+	u32 param4;
+	u32 param5;
+	u32 param6;
+};
+
+#define IPC_RESP_SHIFT			16
+#define IPC_RESP_MASK			(0xffff << 16)
+
+#define M3_VERSION_SHIFT		0
+#define M3_VERSION_MASK			(0xffff << 0)
+
+/*
+ * 9-4 = VTT GPIO PIN (6 Bits)
+ *   3 = VTT Status (1 Bit)
+ * 2-0 = Memory Type (2 Bits)
+*/
+#define MEM_TYPE_SHIFT		(0x0)
+#define MEM_TYPE_MASK		(0x7 << 0)
+#define VTT_STAT_SHIFT		(0x3)
+#define VTT_STAT_MASK		(0x1 << 3)
+#define VTT_GPIO_PIN_SHIFT	(0x4)
+#define VTT_GPIO_PIN_MASK	(0x2f << 4)

arch/arm/mach-omap2/control.h extern void omap3630_ctrl_disable_rta(void); · line 485

Quoted 10 lines
arch/arm/mach-omap2/control.h +10 -0
+
+extern void am33xx_wkup_m3_ipc_cmd(struct am33xx_ipc_data *data);
+extern void am33xx_txev_eoi(void);
+extern void am33xx_txev_enable(void);
+extern void am33xx_pm_version_clear(void);
+extern int am33xx_pm_version_get(void);
+extern void am33xx_pm_ipc_cmd(struct am33xx_ipc_data *data);
+extern int am33xx_pm_status(void);
+extern int am33xx_pm_wake_src(void);
+

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Quoted 3 lines

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Quoted 4 lines

Regards,
Santosh

maintainer
#10 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Regards,

Tony

#11 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 26 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

Quoted 7 lines

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver. The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Regards,
Dave

maintainer
#12 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 5 lines · Dave Gerlach

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver. The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Well maybe try to think how to use these features in a Linux generic way without having to export tons of custom functions?

Regards,

Tony

#13 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

In reply to Dave Gerlach
Quoted 30 lines · Dave Gerlach
Quoted 29 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Quoted 7 lines
Quoted 4 lines

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver.

Any control module register access still needs to stay in control.c.

Quoted 3 lines

The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

I raised this also in earlier reviews, but don't remember the if it was answered...

Why can't we handle the wkup_m3 using remoteproc/rpmsg instead of creating another little driver that duplicates communication with the M3. Note also that the firmware load part would also be provided by remoteproc/rpmsg.

Kevin

#14 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 46 lines · Kevin Hilman
Quoted 30 lines · Dave Gerlach
Quoted 29 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Quoted 7 lines
Quoted 4 lines

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver.

Any control module register access still needs to stay in control.c.

Quoted 3 lines

The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Quoted 7 lines

I raised this also in earlier reviews, but don't remember the if it was answered...

Why can't we handle the wkup_m3 using remoteproc/rpmsg instead of creating another little driver that duplicates communication with the M3. Note also that the firmware load part would also be provided by remoteproc/rpmsg.

Looping Suman Anna who handled the IPC patches this patch set is based on top of...

For the wkup_m3, the mailbox isn't used in a traditional manner. It's only used with a dummy write to trigger an interrupt from the A8 to the M3 and then communication happens in IPC registers within the control module. No messages are actually sent through the mailbox in either direction so that's why it was done this way rather than bring in full support for the mailbox.

Quoted 3 lines

Kevin

#15 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 58 lines · Dave Gerlach
Quoted 46 lines · Kevin Hilman
Quoted 30 lines · Dave Gerlach
Quoted 29 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Quoted 7 lines
Quoted 4 lines

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver.

Any control module register access still needs to stay in control.c.

Quoted 3 lines

The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Quoted 7 lines

I raised this also in earlier reviews, but don't remember the if it was answered...

Why can't we handle the wkup_m3 using remoteproc/rpmsg instead of creating another little driver that duplicates communication with the M3. Note also that the firmware load part would also be provided by remoteproc/rpmsg.

Looping Suman Anna who handled the IPC patches this patch set is based on top of...

Quoted 6 lines

For the wkup_m3, the mailbox isn't used in a traditional manner. It's only used with a dummy write to trigger an interrupt from the A8 to the M3 and then communication happens in IPC registers within the control module. No messages are actually sent through the mailbox in either direction so that's why it was done this way rather than bring in full support for the mailbox.

I don't believe remoteproc/rpmsg forces you to use the mailbox for communication, and can use other IPC mechanisms. This still sounds cleaner than reinventing remoteproc/rpmsg because of slight variations.

The linux way is to use and extend what is already there, and if it's extended to the breaking point, then make a case for why something new is needed.

Kevin

#16 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 67 lines · Kevin Hilman
Quoted 58 lines · Dave Gerlach
Quoted 46 lines · Kevin Hilman
Quoted 30 lines · Dave Gerlach
Quoted 29 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Quoted 7 lines
Quoted 4 lines

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver.

Any control module register access still needs to stay in control.c.

Quoted 3 lines

The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Quoted 7 lines

I raised this also in earlier reviews, but don't remember the if it was answered...

Why can't we handle the wkup_m3 using remoteproc/rpmsg instead of creating another little driver that duplicates communication with the M3. Note also that the firmware load part would also be provided by remoteproc/rpmsg.

Looping Suman Anna who handled the IPC patches this patch set is based on top of...

Quoted 6 lines

For the wkup_m3, the mailbox isn't used in a traditional manner. It's only used with a dummy write to trigger an interrupt from the A8 to the M3 and then communication happens in IPC registers within the control module. No messages are actually sent through the mailbox in either direction so that's why it was done this way rather than bring in full support for the mailbox.

Quoted 8 lines

I don't believe remoteproc/rpmsg forces you to use the mailbox for communication, and can use other IPC mechanisms. This still sounds cleaner than reinventing remoteproc/rpmsg because of slight variations.

The linux way is to use and extend what is already there, and if it's extended to the breaking point, then make a case for why something new is needed.

While I agree to re-use frameworks, am strongly against use of IPC for the power management which is time sensitive. Imagine a scenario where ACPI is asked to go through remoteproc/ipc for talking to firmware. If it takes 10 to 15 uS just to send a command to firmware to change some control, that just tells something is not right and thats what IPC will do.

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general. Specifically for this series, I am also against having tons of exports and all of that should be extracted properly but remoteproc is not going to be the way. Firmware download has to happen much earlier(ROM path) so thats not the requirement where we could have used the remoteproc firmware download feature.

Regards,
Santosh

#17 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

+ Ohad

Quoted 72 lines · Santosh Shilimkar
Quoted 71 lines · Kevin Hilman
Quoted 58 lines · Dave Gerlach
Quoted 46 lines · Kevin Hilman
Quoted 30 lines · Dave Gerlach
Quoted 29 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Quoted 7 lines
Quoted 4 lines

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver.

Any control module register access still needs to stay in control.c.

Quoted 3 lines

The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Quoted 7 lines

I raised this also in earlier reviews, but don't remember the if it was answered...

Why can't we handle the wkup_m3 using remoteproc/rpmsg instead of creating another little driver that duplicates communication with the M3. Note also that the firmware load part would also be provided by remoteproc/rpmsg.

Looping Suman Anna who handled the IPC patches this patch set is based on top of...

Quoted 6 lines

For the wkup_m3, the mailbox isn't used in a traditional manner. It's only used with a dummy write to trigger an interrupt from the A8 to the M3 and then communication happens in IPC registers within the control module. No messages are actually sent through the mailbox in either direction so that's why it was done this way rather than bring in full support for the mailbox.

I don't believe remoteproc/rpmsg forces you to use the mailbox for communication, and can use other IPC mechanisms. This still sounds cleaner than reinventing remoteproc/rpmsg because of slight variations.

Quoted 6 lines
Quoted 4 lines

The linux way is to use and extend what is already there, and if it's extended to the breaking point, then make a case for why something new is needed.

While I agree to re-use frameworks, am strongly against use of IPC for the power management which is time sensitive.

Maybe I'm misunderstanding what you mean by IPC, but I'm not sure how you can be against IPC here. Communication with M3 requires it.

The only question is what framework to use: create a new wkup_m3 driver which creates yet another set of IPC APIs as well as a seprate firmware load path? Or reuse remoteproc/rpmsg which provides both.

Quoted 5 lines

Imagine a scenario where
ACPI is asked to go through remoteproc/ipc for talking to firmware. If it takes 10 to 15 uS just to send a command to firmware to change some control, that just tells something is not right and thats what IPC will do.

Sounds like what you're saying is that remoteproc/rpmsg will be too slow for this? Is there any evidence of that? Even if it is slow, it sounds like a perfect opportuntity to enhance it.

Also, if speed is that much of a concern concern here, I wonder why there's a 500msec timeout in in the communication between MPU and M3 in the current code.

Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

Quoted 5 lines

Specifically for this series, I am also against having tons of exports and all of that should be extracted properly but remoteproc is not going to be the way. Firmware download has to happen much earlier(ROM path) so thats not the requirement where we could have used the remoteproc firmware download feature.

At least for AM33xx, I don't see any requirement that firmware download happens early (or at all.) PM will simply be disabled until firmware is available (and running.)

Kevin

#18 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 83 lines · Kevin Hilman

+ Ohad

Quoted 72 lines · Santosh Shilimkar
Quoted 71 lines · Kevin Hilman
Quoted 58 lines · Dave Gerlach
Quoted 46 lines · Kevin Hilman
Quoted 30 lines · Dave Gerlach
Quoted 29 lines · Tony Lindgren
Quoted 12 lines · Dave Gerlach
Quoted 6 lines · Santosh Shilimkar

Lets address the above better. I don't see a need of 8 functions exported doing one or 2 register writes.

Look M3 based handling is going to be there on future SOCs as well and this kind of handling of IPC is very short cited.

The idea here was to move all control module register accesses into one file in planning of implementing a driver for the control module itself in the future.

Quoted 6 lines
Quoted 2 lines

Probably we should have a separate driver for M3 in linux which can have all this local code instead of all these exports.

The wkup_m3 code has been moved to a small driver found in patch 8 of this series, would it better to move this code there rather than with the rest of the control module code?

Please make everything you can into regular device drivers.

We still have some dependencies to mach-omap2 code for PRCM for example, but we're trying to get all that to live in drivers.

So for new pieces, let's not add further dependencies to complicate moving things to drivers.

Quoted 7 lines
Quoted 4 lines

Regards,

Tony

Ok I will go ahead and pull the control module code that handles IPC into the wkup_m3 driver.

Any control module register access still needs to stay in control.c.

Quoted 3 lines

The wkup_m3.c file is still present in mach-omap2 as the right location for it wasn't decided in the last RFC. Any thoughts on a good location for it?

Quoted 7 lines

I raised this also in earlier reviews, but don't remember the if it was answered...

Why can't we handle the wkup_m3 using remoteproc/rpmsg instead of creating another little driver that duplicates communication with the M3. Note also that the firmware load part would also be provided by remoteproc/rpmsg.

Looping Suman Anna who handled the IPC patches this patch set is based on top of...

Quoted 6 lines

For the wkup_m3, the mailbox isn't used in a traditional manner. It's only used with a dummy write to trigger an interrupt from the A8 to the M3 and then communication happens in IPC registers within the control module. No messages are actually sent through the mailbox in either direction so that's why it was done this way rather than bring in full support for the mailbox.

I don't believe remoteproc/rpmsg forces you to use the mailbox for communication, and can use other IPC mechanisms. This still sounds cleaner than reinventing remoteproc/rpmsg because of slight variations.

Quoted 6 lines
Quoted 4 lines

The linux way is to use and extend what is already there, and if it's extended to the breaking point, then make a case for why something new is needed.

While I agree to re-use frameworks, am strongly against use of IPC for the power management which is time sensitive.

Quoted 7 lines

Maybe I'm misunderstanding what you mean by IPC, but I'm not sure how you can be against IPC here. Communication with M3 requires it.

The only question is what framework to use: create a new wkup_m3 driver which creates yet another set of IPC APIs as well as a seprate firmware load path? Or reuse remoteproc/rpmsg which provides both.

I mean Linux IPC layers.

Quoted 10 lines
Quoted 5 lines

Imagine a scenario where
ACPI is asked to go through remoteproc/ipc for talking to firmware. If it takes 10 to 15 uS just to send a command to firmware to change some control, that just tells something is not right and thats what IPC will do.

Sounds like what you're saying is that remoteproc/rpmsg will be too slow for this? Is there any evidence of that? Even if it is slow, it sounds like a perfect opportuntity to enhance it.

Well 10's uS is fine for the pure IPC kind of messaging. The numbers were measured on Linux OMAP IPC stack for different purpose.

Quoted 4 lines

Also, if speed is that much of a concern concern here, I wonder why there's a 500msec timeout in in the communication between MPU and M3 in the current code.

Quoted 9 lines
Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

I didn't mean for the AM3XXX specifically because its current job is rather very limited. i.e suspend. My concern is that IPC is not viewed as an option for power management controllers like M3 which can abstract all the hardware gory details and export a simpled interface for OS in form of PSCI/ACPI.

Quoted 10 lines
Quoted 5 lines

Specifically for this series, I am also against having tons of exports and all of that should be extracted properly but remoteproc is not going to be the way. Firmware download has to happen much earlier(ROM path) so thats not the requirement where we could have used the remoteproc firmware download feature.

At least for AM33xx, I don't see any requirement that firmware download happens early (or at all.) PM will simply be disabled until firmware is available (and running.)

Thats because its role is pretty much limited. The point was mainly from general PM firmware download strategy and not specifically for this one device.

I just wanted to be sure that we will do all of this for AM3XXX and expect the future SOCs to follow that model where M3 would have more prominent role and more and more hardware sequencing for HLOS.

Regards,
Santosh

#19 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

Quoted 5 lines

I didn't mean for the AM3XXX specifically because its current job is rather very limited. i.e suspend. My concern is that IPC is not viewed as an option for power management controllers like M3 which can abstract all the hardware gory details and export a simpled interface for OS in form of PSCI/ACPI.

The IPC between the M3 and the A8 on the am335x is just a pair of notification mechanisms (one from the A8, mailbox, and one from the M3, sev) and a set of 8 32 bit registers. The 8 32 bit registers are just a scratchpad and have no access rules or functionality beyond being a scratchpad. How complicated do we want to make this?

#20 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 15 lines · Russ Dill
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

Quoted 5 lines

I didn't mean for the AM3XXX specifically because its current job is rather very limited. i.e suspend. My concern is that IPC is not viewed as an option for power management controllers like M3 which can abstract all the hardware gory details and export a simpled interface for OS in form of PSCI/ACPI.

Quoted 6 lines

The IPC between the M3 and the A8 on the am335x is just a pair of notification mechanisms (one from the A8, mailbox, and one from the M3, sev) and a set of 8 32 bit registers. The 8 32 bit registers are just a scratchpad and have no access rules or functionality beyond being a scratchpad. How complicated do we want to make this?

Exactly what I mean as well.

Regards,
Santosh

#21 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

In reply to Russ Dill
Quoted 15 lines · Russ Dill
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

Quoted 5 lines

I didn't mean for the AM3XXX specifically because its current job is rather very limited. i.e suspend. My concern is that IPC is not viewed as an option for power management controllers like M3 which can abstract all the hardware gory details and export a simpled interface for OS in form of PSCI/ACPI.

Quoted 5 lines

The IPC between the M3 and the A8 on the am335x is just a pair of notification mechanisms (one from the A8, mailbox, and one from the M3, sev) and a set of 8 32 bit registers. The 8 32 bit registers are just a scratchpad and have no access rules or functionality beyond being a scratchpad. How complicated do we want to make this?

The OMAP IPC between the MPU and DSP (read: any other remote processor) is just a mailbox and some shared memory. No complicated, and works with remoteproc/rpmsg.

What's more complicated? reusing existing frameworks or re-inventing them? Don't forget that "simple" drivers rarely stay that way.

Also, this is not a hard stance on my part. I just need to be convinced.

The fact is that there are existing frameworks for doing what is being proposed here. Either use the existing frameworks, or make a technical argument based on why those frameworks are not a good fit (ideally, after having tried to use those frameworks.)

Once again, I'm pretty sure I mentioned this in earlier reviews of this series.

Kevin

#22 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Kevin, Santosh, Dave, Russ,

Quoted 23 lines · Kevin Hilman
Quoted 15 lines · Russ Dill
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

Quoted 5 lines

I didn't mean for the AM3XXX specifically because its current job is rather very limited. i.e suspend. My concern is that IPC is not viewed as an option for power management controllers like M3 which can abstract all the hardware gory details and export a simpled interface for OS in form of PSCI/ACPI.

Quoted 5 lines

The IPC between the M3 and the A8 on the am335x is just a pair of notification mechanisms (one from the A8, mailbox, and one from the M3, sev) and a set of 8 32 bit registers. The 8 32 bit registers are just a scratchpad and have no access rules or functionality beyond being a scratchpad. How complicated do we want to make this?

Quoted 3 lines

The OMAP IPC between the MPU and DSP (read: any other remote processor) is just a mailbox and some shared memory. No complicated, and works with remoteproc/rpmsg.

I had to catch up on all the threads before I responded, but here are my notes regarding using remoteproc/rpmsg infrastructure for WkupM3. It definitely brings in lot more complexity than what's present today. The WkupM3 in AM335x does not have the same feature set as the Cortex-M3s used within the IPU in OMAP4+ SoCs. It does not have an MMU and peripheral accesses seems to be limited to just those in L4_Wkup domain.

A lot actually depends on whether the WkupM3 can use DDR. I am not sure if there are any restrictions on WkupM3 from where it could run the code or access data from. From what I can gather from the TRM (there's no big separate chapter on WkupM3), it has just 16K UMEM and a 8K DMEM, and its not much. The current firmware is loaded directly into the WkupM3's internal UMem space and a check is being performed to make sure the firmware is less than 16K, so that it can fit into UMem.

The remoteproc infrastructure is currently tied closely with the virtio/rpmsg framework, and the boot requires that there are virtio devices present in the resource table from the firmware image. The rpmsg shared memory buffers are currently kinda fixed (512 buffers of 512 bytes each) and requires 3 pages just for the vring structures for this many buffers. So, if there are restrictions on DDR access, then this pretty much rules out remoteproc/rpmsg infrastructure.

If the DDR access is ok, then there are other challenges that needs to be met. The current firmware definitely requires the addition of the resource table and the lower level code for handling the virtio_ring transport for receiving messages. It would also need its own remoteproc driver for handling the firmware binary format and the signalling required to trigger the rpmsg buffer processing. The firmware binary format needs to be adapted to something that this driver would understand. It definitely doesn't look like ELF currently, so something on the lines of ste_modem_rproc needs to be done. Also, the remoteproc/rpmsg infrastructure can support multiple vring transport channels between the processor, and depending on how many are supported, we either need to exchange the vq_id (like OMAP remoteproc), or process the known virtqueues always (like DA8xx remoteproc). The former requires that a message payload is used, and mandates the usage of the IPC data registers in the control module given that WkupM3 on AM335 cannot access any mailbox registers. Any usage of IPC data registers depends on where we do it. If all the accesses were to be done within mach-omap2/control.c, then there is no easy way for using this API from drivers/remoteproc, until we have the control module driver. I do feel that this needs to be done within the wkup_m3 driver currently. This would be no different to the crossbar driver example on DRA7, which also has to deal with registers in Control module. The IPC data registers do not have any associated interrupts by itself, so just making this a standalone driver is also not possible. Also, the dependencies with using the omap_device API for dealing with the hard reset lines needs to be dealt with.

The current communication uses the IPC data registers, and sometimes uses them as plain status registers. There's certain registers used for sharing status, version etc which are shared by both the processors. Using rpmsg would require communicating every single message, and if there were to be some shared variables to be used simultaneously, then this has to be exchanged through a new remoteproc resource type.

One additional aspect is that the current remoteproc core does not have the necessary runtime pm support, but in general the approach would be to treat the remoteprocs as true slave devices. I would imagine the driver core to put the remoteprocs into reset state, after asking them to save their context during suspend.

regards
Suman

#23 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Quoted 37 lines · Suman Anna

Kevin, Santosh, Dave, Russ,

Quoted 23 lines · Kevin Hilman
Quoted 15 lines · Russ Dill
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

ARM world is also moving towards that by standardizing some of these through (read PSCI) and thats the way to go in general.

Agreed, but I'm not sure (yet) about enforcing PSCI on legacy platforms that don't support it natively. Are you saying that the AM33xx firmware should be converted to be PSCI compliant? Admittedly, I haven't read the PSCI spec closely, but I'm wondering if the current role splitting between MPU and M3 fits well with PSCI.

Quoted 5 lines

I didn't mean for the AM3XXX specifically because its current job is rather very limited. i.e suspend. My concern is that IPC is not viewed as an option for power management controllers like M3 which can abstract all the hardware gory details and export a simpled interface for OS in form of PSCI/ACPI.

Quoted 5 lines

The IPC between the M3 and the A8 on the am335x is just a pair of notification mechanisms (one from the A8, mailbox, and one from the M3, sev) and a set of 8 32 bit registers. The 8 32 bit registers are just a scratchpad and have no access rules or functionality beyond being a scratchpad. How complicated do we want to make this?

Quoted 3 lines

The OMAP IPC between the MPU and DSP (read: any other remote processor) is just a mailbox and some shared memory. No complicated, and works with remoteproc/rpmsg.

I had to catch up on all the threads before I responded, but here are my notes regarding using remoteproc/rpmsg infrastructure for WkupM3. It definitely brings in lot more complexity than what's present today. The WkupM3 in AM335x does not have the same feature set as the Cortex-M3s used within the IPU in OMAP4+ SoCs. It does not have an MMU and peripheral accesses seems to be limited to just those in L4_Wkup domain.

Quoted 7 lines

A lot actually depends on whether the WkupM3 can use DDR. I am not sure if there are any restrictions on WkupM3 from where it could run the code or access data from. From what I can gather from the TRM (there's no big separate chapter on WkupM3), it has just 16K UMEM and a 8K DMEM, and its not much. The current firmware is loaded directly into the WkupM3's internal UMem space and a check is being performed to make sure the firmware is less than 16K, so that it can fit into UMem.

Even if the WkupM3 could access DMEM, it would defeat the whole purpose of using it, as it lives to do things like enable VTP, but the EMIF clocks into bypass, turn off the power domain the EMIF is contained in, etc.

Quoted 51 lines

The remoteproc infrastructure is currently tied closely with the virtio/rpmsg framework, and the boot requires that there are virtio devices present in the resource table from the firmware image. The rpmsg shared memory buffers are currently kinda fixed (512 buffers of 512 bytes each) and requires 3 pages just for the vring structures for this many buffers. So, if there are restrictions on DDR access, then this pretty much rules out remoteproc/rpmsg infrastructure.

If the DDR access is ok, then there are other challenges that needs to be met. The current firmware definitely requires the addition of the resource table and the lower level code for handling the virtio_ring transport for receiving messages. It would also need its own remoteproc driver for handling the firmware binary format and the signalling required to trigger the rpmsg buffer processing. The firmware binary format needs to be adapted to something that this driver would understand. It definitely doesn't look like ELF currently, so something on the lines of ste_modem_rproc needs to be done. Also, the remoteproc/rpmsg infrastructure can support multiple vring transport channels between the processor, and depending on how many are supported, we either need to exchange the vq_id (like OMAP remoteproc), or process the known virtqueues always (like DA8xx remoteproc). The former requires that a message payload is used, and mandates the usage of the IPC data registers in the control module given that WkupM3 on AM335 cannot access any mailbox registers. Any usage of IPC data registers depends on where we do it. If all the accesses were to be done within mach-omap2/control.c, then there is no easy way for using this API from drivers/remoteproc, until we have the control module driver. I do feel that this needs to be done within the wkup_m3 driver currently. This would be no different to the crossbar driver example on DRA7, which also has to deal with registers in Control module. The IPC data registers do not have any associated interrupts by itself, so just making this a standalone driver is also not possible. Also, the dependencies with using the omap_device API for dealing with the hard reset lines needs to be dealt with.

The current communication uses the IPC data registers, and sometimes uses them as plain status registers. There's certain registers used for sharing status, version etc which are shared by both the processors. Using rpmsg would require communicating every single message, and if there were to be some shared variables to be used simultaneously, then this has to be exchanged through a new remoteproc resource type.

One additional aspect is that the current remoteproc core does not have the necessary runtime pm support, but in general the approach would be to treat the remoteprocs as true slave devices. I would imagine the driver core to put the remoteprocs into reset state, after asking them to save their context during suspend.

regards
Suman

#24 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

In reply to Suman Anna

Hi

a few comments

Quoted 3 lines · Suman Anna

The remoteproc infrastructure is currently tied closely with the virtio/rpmsg framework, and the boot requires that there are virtio devices present in the resource table from the firmware image.

Using static channels is something that can be added to the existing code, if you don't want to use dynamic channels.

Quoted 4 lines

The rpmsg shared memory buffers are currently kinda fixed (512 buffers of 512 bytes each) and requires 3 pages just for the vring structures for this many buffers. So, if there are restrictions on DDR access, then this pretty much rules out remoteproc/rpmsg infrastructure.

It should be possible to patch that code to vary the size and count of the memory buffers, based on the remote processor. So no direct DDR access should be required - for that reason, anyway.

Quoted 5 lines

If the DDR access is ok, then there are other challenges that needs to be met. The current firmware definitely requires the addition of the resource table and the lower level code for handling the virtio_ring transport for receiving messages. It would also need its own remoteproc driver for handling the firmware binary format

Hmm, could you explain this further? Are you just referring to the process of parsing out the dynamic channel data during initialization?

Quoted 4 lines

and the signalling required to trigger the rpmsg buffer processing. The firmware binary format needs to be adapted to something that this driver would understand. It definitely doesn't look like ELF currently, so something on the lines of ste_modem_rproc needs to be done.

Or just use ELF or static channels.

Quoted 10 lines

Also, the remoteproc/rpmsg infrastructure can support multiple vring transport channels between the processor, and depending on how many are supported, we either need to exchange the vq_id (like OMAP remoteproc), or process the known virtqueues always (like DA8xx remoteproc). The former requires that a message payload is used, and mandates the usage of the IPC data registers in the control module given that WkupM3 on AM335 cannot access any mailbox registers. Any usage of IPC data registers depends on where we do it. If all the accesses were to be done within mach-omap2/control.c, then there is no easy way for using this API from drivers/remoteproc, until we have the control module driver.

Yep, real SCM drivers have been needed for some time now, for pretty much all of the OMAP SoCs. It should be pretty easy to prototype for your purposes, though.

Quoted 6 lines

The current communication uses the IPC data registers, and sometimes uses them as plain status registers. There's certain registers used for sharing status, version etc which are shared by both the processors. Using rpmsg would require communicating every single message, and if there were to be some shared variables to be used simultaneously, then this has to be exchanged through a new remoteproc resource type.

I don't quite understand this last part - "shared variables to be used simultaneously". How does the existing code synchronize them?

Quoted 5 lines

One additional aspect is that the current remoteproc core does not have the necessary runtime pm support, but in general the approach would be to treat the remoteprocs as true slave devices. I would imagine the driver core to put the remoteprocs into reset state, after asking them to save their context during suspend.

Why is runtime PM support needed in the remoteproc core? Wouldn't that only be needed in the remote processor's device driver?

- Paul

#25 lore raw

PATCH v3 2/9 ARM: OMAP2+: AM33XX: control: Add some control module registers and APIs

Paul,

Quoted 4 lines · Paul Walmsley

Hi

a few comments

Quoted 8 lines
Quoted 3 lines · Suman Anna

The remoteproc infrastructure is currently tied closely with the virtio/rpmsg framework, and the boot requires that there are virtio devices present in the resource table from the firmware image.

Using static channels is something that can be added to the existing code, if you don't want to use dynamic channels.

The resource table is used for both indicating the remoteproc resources as well as allowing the driver to publish the data back so that the remote processor can configure itself. The virtio devices do have other configuration fields and this allows the driver to update the status fields which the remote processor can read. This functionality is definitely lost if we use static virtio devices.

Also, the remoteproc boot is a two-step process currently. It reads the virtio device information from the resource table and creates the virtio devices. The virtio device probe then triggers the remoteproc boot, which processes the firmware segments and handles the actual processor boot. The memory for firmware segments are allocated through CMA and the allocated addresses are published through the resource table to the remote processor-side. The core definitely needs to be patched up to support loading internal memory segments.

Quoted 9 lines
Quoted 5 lines

The rpmsg shared memory buffers are currently kinda fixed (512 buffers of 512 bytes each) and requires 3 pages just for the vring structures for this many buffers. So, if there are restrictions on DDR access, then this pretty much rules out remoteproc/rpmsg infrastructure.

It should be possible to patch that code to vary the size and count of the memory buffers, based on the remote processor. So no direct DDR access should be required - for that reason, anyway.

Yep, I agree that this needs to be programmable. Support needs to be added to both the remoteproc and rpmsg cores to deal with internal memory for the vrings and vring buffers. Currently, it is all allocated dynamically through CMA. That said, the WkupM3 really has a very small memory regions, 16K of UMEM and 8K of DMEM. Everything has to fit within that including the vrings and vring buffers. I have to check if there are alignment restrictions imposed by the virtio code on the vrings and if that overshoots the available internal memory.

Quoted 9 lines
Quoted 6 lines

If the DDR access is ok, then there are other challenges that needs to be met. The current firmware definitely requires the addition of the resource table and the lower level code for handling the virtio_ring transport for receiving messages. It would also need its own remoteproc driver for handling the firmware binary format

Hmm, could you explain this further? Are you just referring to the process of parsing out the dynamic channel data during initialization?

Yes, for parsing out where the resource table is. The remoteproc core provides the necessary hooks for finding the resource table and loading the firmware segments. If the firmware file is gonna remain a binary blob, then these hooks need to be implemented for that binary format. No issues if it were an ELF file, since we expect the resource table to be present in a special section.

Quoted 7 lines
Quoted 5 lines

and the signalling required to trigger the rpmsg buffer processing. The firmware binary format needs to be adapted to something that this driver would understand. It definitely doesn't look like ELF currently, so something on the lines of ste_modem_rproc needs to be done.

Or just use ELF or static channels.

I have taken a look at the firmware tree, and the binary is generated from an ELF file, so the format is not an issue as long as the memory footprint is satisfied. static channels is more of an issue as pointed above.

Quoted 23 lines
Quoted 11 lines

Also, the remoteproc/rpmsg infrastructure can support multiple vring transport channels between the processor, and depending on how many are supported, we either need to exchange the vq_id (like OMAP remoteproc), or process the known virtqueues always (like DA8xx remoteproc). The former requires that a message payload is used, and mandates the usage of the IPC data registers in the control module given that WkupM3 on AM335 cannot access any mailbox registers. Any usage of IPC data registers depends on where we do it. If all the accesses were to be done within mach-omap2/control.c, then there is no easy way for using this API from drivers/remoteproc, until we have the control module driver.

Yep, real SCM drivers have been needed for some time now, for pretty much all of the OMAP SoCs. It should be pretty easy to prototype for your purposes, though.

Quoted 6 lines

The current communication uses the IPC data registers, and sometimes uses them as plain status registers. There's certain registers used for sharing status, version etc which are shared by both the processors. Using rpmsg would require communicating every single message, and if there were to be some shared variables to be used simultaneously, then this has to be exchanged through a new remoteproc resource type.

Quoted 2 lines

I don't quite understand this last part - "shared variables to be used simultaneously". How does the existing code synchronize them?

The IPC data registers are just like regular registers, values written in them stay that way until changed. The current PM code uses some of these registers as fixed status variables, while some of them are changed based on the state machine, and an interrupt is sent to process that PM command. The message payload is well within these 8 registers for the needs of PM.

Quoted 9 lines
Quoted 6 lines

One additional aspect is that the current remoteproc core does not have the necessary runtime pm support, but in general the approach would be to treat the remoteprocs as true slave devices. I would imagine the driver core to put the remoteprocs into reset state, after asking them to save their context during suspend.

Why is runtime PM support needed in the remoteproc core? Wouldn't that only be needed in the remote processor's device driver?

The actual low-level operations would be in the remote processor's device driver, but since the core maintains the overall device management including loading and state machine, doing it in the core would be nice as it provides a common base logic (can be implemented through device type and ops) instead of replicating it in every device driver.

regards
Suman

#26 lore raw

PATCH v3 3/9 ARM: OMAP: DTB: Update IRQ data for WKUP_M3

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Allow interrupt for wkup_m3 to be set from DT.

---
 arch/arm/boot/dts/am33xx.dtsi |    1 +
 1 file changed, 1 insertion(+)
arch/arm/boot/dts/am33xx.dtsi +1 -0
index 38b446b..05353bf 100644
@@ -491,6 +491,7 @@
 			compatible = "ti,am3353-wkup-m3";
 			reg = <0x44d00000 0x4000	/* M3 UMEM */
 			       0x44d80000 0x2000>;	/* M3 DMEM */
+			interrupts = <78>;
 			ti,hwmods = "wkup_m3";
 		};
 
Signature · 1 line
1.7.9.5
#27 lore raw

PATCH v3 3/9 ARM: OMAP: DTB: Update IRQ data for WKUP_M3

Quoted 7 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Allow interrupt for wkup_m3 to be set from DT.

Quoted 23 lines
---
 arch/arm/boot/dts/am33xx.dtsi |    1 +
 1 file changed, 1 insertion(+)
arch/arm/boot/dts/am33xx.dtsi +1 -1
index 38b446b..05353bf 100644
@@ -491,6 +491,7 @@
                        compatible = "ti,am3353-wkup-m3";
                        reg = <0x44d00000 0x4000        /* M3 UMEM */
                               0x44d80000 0x2000>;      /* M3 DMEM */
+                       interrupts = <78>;
                        ti,hwmods = "wkup_m3";
                };
 
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#29 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

A subsequent patch will pass along the location of the reserved memory location to the AM335x suspend handler which modifies the PWR_MGMT_CTRL register in the EMIF.

---
 arch/arm/mach-omap2/board-generic.c |    2 +-
 arch/arm/mach-omap2/common.c        |   28 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/common.h        |    4 ++++
 arch/arm/mach-omap2/io.c            |    1 +
 4 files changed, 34 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-generic.c +1 -1
index be5d005..aed750c 100644
@@ -156,7 +156,7 @@ static const char *am33xx_boards_compat[] __initdata = {
 };
 
 DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
-	.reserve	= omap_reserve,
+	.reserve	= am33xx_reserve,
 	.map_io		= am33xx_map_io,
 	.init_early	= am33xx_init_early,
 	.init_irq	= omap_intc_of_init,
arch/arm/mach-omap2/common.c +28 -0
index 2dabb9e..756586f 100644
@@ -15,6 +15,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_data/dsp-omap.h>
+#include <asm/memblock.h>
+#include <asm/mach/map.h>
 
 #include "common.h"
 #include "omap-secure.h"
@@ -34,3 +36,29 @@ void __init omap_reserve(void)
 	omap_secure_ram_reserve_memblock();
 	omap_barrier_reserve_memblock();
 }
+
+static phys_addr_t am33xx_paddr;
+static u32 am33xx_size;
+
+/* Steal one page physical memory for uncached read DeepSleep */
+void __init am33xx_reserve(void)
+{
+	am33xx_size = ALIGN(PAGE_SIZE, SZ_1M);
+	am33xx_paddr = arm_memblock_steal(am33xx_size, SZ_1M);
+}
+
+void __iomem *am33xx_dram_sync;
+
+void __init am33xx_dram_sync_init(void)
+{
+	struct map_desc dram_io_desc[1];
+
+	dram_io_desc[0].virtual = __phys_to_virt(am33xx_paddr);
+	dram_io_desc[0].pfn = __phys_to_pfn(am33xx_paddr);
+	dram_io_desc[0].length = am33xx_size;
+	dram_io_desc[0].type = MT_MEMORY_SO;
+
+	iotable_init(dram_io_desc, ARRAY_SIZE(dram_io_desc));
+
+	am33xx_dram_sync = (void __iomem *) dram_io_desc[0].virtual;
+}
arch/arm/mach-omap2/common.h +4 -0
index dfcc182..6b8ef74 100644
@@ -294,6 +294,10 @@ struct omap2_hsmmc_info;
 extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers);
 extern void omap_reserve(void);
 
+extern void am33xx_reserve(void);
+extern void am33xx_dram_sync_init(void);
+extern void __iomem *am33xx_dram_sync;
+
 struct omap_hwmod;
 extern int omap_dss_reset(struct omap_hwmod *);
 
arch/arm/mach-omap2/io.c +1 -0
index 4a3f06f..3ad7543 100644
@@ -322,6 +322,7 @@ void __init ti81xx_map_io(void)
 void __init am33xx_map_io(void)
 {
 	iotable_init(omapam33xx_io_desc, ARRAY_SIZE(omapam33xx_io_desc));
+	am33xx_dram_sync_init();
 }
 #endif
 
Signature · 1 line
1.7.9.5
#30 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

Quoted 9 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Quoted 6 lines

A subsequent patch will pass along the location of the reserved memory location to the AM335x suspend handler which modifies the PWR_MGMT_CTRL register in the EMIF.

Quoted 97 lines
---
 arch/arm/mach-omap2/board-generic.c |    2 +-
 arch/arm/mach-omap2/common.c        |   28 ++++++++++++++++++++++++++++
 arch/arm/mach-omap2/common.h        |    4 ++++
 arch/arm/mach-omap2/io.c            |    1 +
 4 files changed, 34 insertions(+), 1 deletion(-)
arch/arm/mach-omap2/board-generic.c +1 -1
index be5d005..aed750c 100644
@@ -156,7 +156,7 @@ static const char *am33xx_boards_compat[] __initdata = {
 };
 
 DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
-       .reserve        = omap_reserve,
+       .reserve        = am33xx_reserve,
        .map_io         = am33xx_map_io,
        .init_early     = am33xx_init_early,
        .init_irq       = omap_intc_of_init,
arch/arm/mach-omap2/common.c +28 -0
index 2dabb9e..756586f 100644
@@ -15,6 +15,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_data/dsp-omap.h>
+#include <asm/memblock.h>
+#include <asm/mach/map.h>
 
 #include "common.h"
 #include "omap-secure.h"
@@ -34,3 +36,29 @@ void __init omap_reserve(void)
        omap_secure_ram_reserve_memblock();
        omap_barrier_reserve_memblock();
 }
+
+static phys_addr_t am33xx_paddr;
+static u32 am33xx_size;
+
+/* Steal one page physical memory for uncached read DeepSleep */
+void __init am33xx_reserve(void)
+{
+       am33xx_size = ALIGN(PAGE_SIZE, SZ_1M);
+       am33xx_paddr = arm_memblock_steal(am33xx_size, SZ_1M);
+}
+
+void __iomem *am33xx_dram_sync;
+
+void __init am33xx_dram_sync_init(void)
+{
+       struct map_desc dram_io_desc[1];
+
+       dram_io_desc[0].virtual = __phys_to_virt(am33xx_paddr);
+       dram_io_desc[0].pfn = __phys_to_pfn(am33xx_paddr);
+       dram_io_desc[0].length = am33xx_size;
+       dram_io_desc[0].type = MT_MEMORY_SO;
+
+       iotable_init(dram_io_desc, ARRAY_SIZE(dram_io_desc));
+
+       am33xx_dram_sync = (void __iomem *) dram_io_desc[0].virtual;
+}
arch/arm/mach-omap2/common.h +4 -0
index dfcc182..6b8ef74 100644
@@ -294,6 +294,10 @@ struct omap2_hsmmc_info;
 extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers);
 extern void omap_reserve(void);
 
+extern void am33xx_reserve(void);
+extern void am33xx_dram_sync_init(void);
+extern void __iomem *am33xx_dram_sync;
+
 struct omap_hwmod;
 extern int omap_dss_reset(struct omap_hwmod *);
 
arch/arm/mach-omap2/io.c +1 -1
index 4a3f06f..3ad7543 100644
@@ -322,6 +322,7 @@ void __init ti81xx_map_io(void)
 void __init am33xx_map_io(void)
 {
        iotable_init(omapam33xx_io_desc, ARRAY_SIZE(omapam33xx_io_desc));
+       am33xx_dram_sync_init();
 }
 #endif
 
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#31 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

In reply to Dave Gerlach
Quoted 9 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Quoted 7 lines

A subsequent patch will pass along the location of the reserved memory location to the AM335x suspend handler which modifies the PWR_MGMT_CTRL register in the EMIF.

---

#32 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

In reply to Dave Gerlach
Quoted 8 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Hmm, sounds to me an awful lot like the existing omap_bus_sync() ?

However, you remove that feature when you remove omap_reserve() here becasue omap_reserve() ss not called from your new reserve function. Are you *really* sure you don't need the functions called there? This is a pretty big change that's not mentioned anywhere in the changelog.

Kevin

#33 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

Quoted 4 lines · Kevin Hilman
Quoted 2 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Quoted 9 lines
Quoted 6 lines

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Hmm, sounds to me an awful lot like the existing omap_bus_sync() ?

All the credit of that awful omap_bus_sync() goes to me since I introduced it. And I keep beating the hardware guys who have not left a choice but to introduce the ugly work around in software. ;-)

Regards,
Santosh

#34 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

Quoted 12 lines · Santosh Shilimkar
Quoted 11 lines · Kevin Hilman
Quoted 8 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Quoted 6 lines
Quoted 2 lines

Hmm, sounds to me an awful lot like the existing omap_bus_sync() ?

All the credit of that awful omap_bus_sync() goes to me since I introduced it. And I keep beating the hardware guys who have not left a choice but to introduce the ugly work around in software. ;-)

Agreed, but what's even more awful than the current version is duplicating it in a slightly different way using yet another whole page mapping for a single read/write location.

Kevin

#35 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

Quoted 16 lines · Kevin Hilman
Quoted 14 lines · Santosh Shilimkar
Quoted 13 lines · Kevin Hilman
Quoted 8 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Hmm, sounds to me an awful lot like the existing omap_bus_sync() ?

Quoted 9 lines
Quoted 4 lines

All the credit of that awful omap_bus_sync() goes to me since I introduced it. And I keep beating the hardware guys who have not left a choice but to introduce the ugly work around in software. ;-)

Agreed, but what's even more awful than the current version is duplicating it in a slightly different way using yet another whole page mapping for a single read/write location.

The real issue is limitation of the kernel memory steal(memblock) API which won't let you still less than 1 MB. It would have been ok for page allocation because that is any way what you will get minimum on standard non-cached allocations.

Regards,
Santosh

#36 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

Quoted 22 lines · Santosh Shilimkar
Quoted 21 lines · Kevin Hilman
Quoted 18 lines · Santosh Shilimkar
Quoted 4 lines · Kevin Hilman
Quoted 2 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Quoted 9 lines
Quoted 6 lines

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Hmm, sounds to me an awful lot like the existing omap_bus_sync() ?

All the credit of that awful omap_bus_sync() goes to me since I introduced it. And I keep beating the hardware guys who have not left a choice but to introduce the ugly work around in software. ;-)

Quoted 8 lines
Quoted 4 lines

Agreed, but what's even more awful than the current version is duplicating it in a slightly different way using yet another whole page mapping for a single read/write location.

The real issue is limitation of the kernel memory steal(memblock) API which won't let you still less than 1 MB. It would have been ok for page allocation because that is any way what you will get minimum on standard non-cached allocations.

All the more reason that the omap_bus_sync() should be refactored slightly in a way that would be reusable for AM33xx.

Kevin

#37 lore raw

PATCH v3 4/9 ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec

Quoted 33 lines · Kevin Hilman
Quoted 22 lines · Santosh Shilimkar
Quoted 21 lines · Kevin Hilman
Quoted 18 lines · Santosh Shilimkar
Quoted 4 lines · Kevin Hilman
Quoted 2 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Quoted 9 lines
Quoted 6 lines

SDRAM controller on AM33XX requires that a modification of certain bit-fields in PWR_MGMT_CTRL register (ref. section 7.3.5.13 in AM335x-Rev H) is followed by a dummy read access to SDRAM. This scenario arises when entering a low power state like DeepSleep. To ensure that the read is not from a cached region we reserve some memory during bootup using the arm_memblock_steal() API.

Hmm, sounds to me an awful lot like the existing omap_bus_sync() ?

All the credit of that awful omap_bus_sync() goes to me since I introduced it. And I keep beating the hardware guys who have not left a choice but to introduce the ugly work around in software. ;-)

Quoted 8 lines
Quoted 4 lines

Agreed, but what's even more awful than the current version is duplicating it in a slightly different way using yet another whole page mapping for a single read/write location.

The real issue is limitation of the kernel memory steal(memblock) API which won't let you still less than 1 MB. It would have been ok for page allocation because that is any way what you will get minimum on standard non-cached allocations.

Quoted 5 lines

All the more reason that the omap_bus_sync() should be refactored slightly in a way that would be reusable for AM33xx.

Kevin

I will look in to doing it this way. I do not know if there was any specific reason for doing it the way it was done.

Dave

#38 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

If no interrupts have come, WFI execution on MPU gets registered as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes care of clockdomain and powerdomain transitions as part of the DeepSleep0 mode entry.

In case a late interrupt comes in, WFI ends up as a NOP and MPU continues execution from internal memory. The 'abort path' code undoes whatever was done as part of the low power entry and indicates a suspend failure by passing a non-zero value to the cpu_resume routine.

The 'resume path' code is similar to the 'abort path' with the key difference of MMU being enabled in the 'abort path' but being disabled in the 'resume path' due to MPU getting powered off.

Cc Santosh Shilimkar <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/sleep33xx.S |  350 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep33xx.S new file +350 -0
new file mode 100644
index 0000000..834c7d4
@@ -0,0 +1,350 @@
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/ti_emif.h>
+#include <asm/memory.h>
+#include <asm/assembler.h>
+
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "prm33xx.h"
+
+	.text
+	.align 3
+
+/*
+ * This routine is executed from internal RAM and expects some
+ * parameters to be passed in r0 _strictly_ in following order:
+ * 1) emif_addr_virt - ioremapped EMIF address
+ * 2) mem_type - 2 -> DDR2, 3-> DDR3
+ * 3) dram_sync_word - uncached word in SDRAM
+ *
+ * The code loads these values taking r0 value as reference to
+ * the array in registers starting from r0, i.e emif_addr_virt
+ * goes to r1, mem_type goes to r2 and and so on. These are
+ * then saved into memory locations before proceeding with the
+ * sleep sequence and hence registers r0, r1 etc can still be
+ * used in the rest of the sleep code.
+ */
+
+ENTRY(am33xx_do_wfi)
+	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
+
+	ldm	r0, {r1-r3}		@ gather values passed
+
+	/* Save the values passed */
+	str	r1, emif_addr_virt
+	str	r2, mem_type
+	str	r3, dram_sync_word
+
+	/*
+	 * Flush all data from the L1 data cache before disabling
+	 * SCTLR.C bit.
+	 */
+	ldr	r1, kernel_flush
+	blx	r1
+
+	/*
+	 * Clear the SCTLR.C bit to prevent further data cache
+	 * allocation. Clearing SCTLR.C would make all the data accesses
+	 * strongly ordered and would not hit the cache.
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #(1 << 2)	@ Disable the C bit
+	mcr	p15, 0, r0, c1, c0, 0
+	isb
+
+	/*
+	 * Invalidate L1 data cache. Even though only invalidate is
+	 * necessary exported flush API is used here. Doing clean
+	 * on already clean cache would be almost NOP.
+	 */
+	ldr	r1, kernel_flush
+	blx	r1
+
+	ldr	r0, emif_addr_virt
+	/* Save EMIF configuration */
+	ldr	r1, [r0, #EMIF_SDRAM_CONFIG]
+	str	r1, emif_sdcfg_val
+	ldr	r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+	str	r1, emif_ref_ctrl_val
+	ldr	r1, [r0, #EMIF_SDRAM_TIMING_1]
+	str	r1, emif_timing1_val
+	ldr	r1, [r0, #EMIF_SDRAM_TIMING_2]
+	str	r1, emif_timing2_val
+	ldr	r1, [r0, #EMIF_SDRAM_TIMING_3]
+	str	r1, emif_timing3_val
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	str	r1, emif_pmcr_val
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+	str	r1, emif_pmcr_shdw_val
+	ldr	r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+	str	r1, emif_zqcfg_val
+	ldr	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+	str	r1, emif_rd_lat_val
+
+	/* Put SDRAM in self-refresh */
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	orr	r1, r1, #0xa0
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+	str	r1, [r0, #4]
+
+	ldr	r1, dram_sync_word	@ a dummy access to DDR as per spec
+	ldr	r2, [r1, #0]
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	orr	r1, r1, #0x200
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+	mov	r1, #0x1000		@ Wait for system to enter SR
+wait_sr:
+	subs	r1, r1, #1
+	bne	wait_sr
+
+	/* Disable EMIF */
+	ldr	r1, virt_emif_clkctrl
+	ldr	r2, [r1]
+	bic	r2, r2, #0x03
+	str	r2, [r1]
+
+	ldr	r1, virt_emif_clkctrl
+wait_emif_disable:
+	ldr	r2, [r1]
+	ldr	r3, module_disabled_val
+	cmp	r2, r3
+	bne	wait_emif_disable
+
+	/*
+	 * For the MPU WFI to be registered as an interrupt
+	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
+	 * to DISABLED
+	 */
+	ldr	r1, virt_mpu_clkctrl
+	ldr	r2, [r1]
+	bic	r2, r2, #0x03
+	str	r2, [r1]
+
+	/*
+	 * Execute an ISB instruction to ensure that all of the
+	 * CP15 register changes have been committed.
+	 */
+	isb
+
+	/*
+	 * Execute a barrier instruction to ensure that all cache,
+	 * TLB and branch predictor maintenance operations issued
+	 * have completed.
+	 */
+	dsb
+	dmb
+
+	/*
+	 * Execute a WFI instruction and wait until the
+	 * STANDBYWFI output is asserted to indicate that the
+	 * CPU is in idle and low power state. CPU can specualatively
+	 * prefetch the instructions so add NOPs after WFI. Thirteen
+	 * NOPs as per Cortex-A8 pipeline.
+	 */
+	wfi
+
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	/* We come here in case of an abort due to a late interrupt */
+
+	/* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
+	ldr	r1, virt_mpu_clkctrl
+	mov	r2, #0x02
+	str	r2, [r1]
+
+	/* Re-enable EMIF */
+	ldr	r1, virt_emif_clkctrl
+	mov	r2, #0x02
+	str	r2, [r1]
+wait_emif_enable:
+	ldr	r3, [r1]
+	cmp	r2, r3
+	bne	wait_emif_enable
+
+	/* Disable EMIF self-refresh */
+	ldr	r0, emif_addr_virt
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	bic	r1, r1, #LP_MODE_MASK
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+	/*
+	 * A write to SDRAM CONFIG register triggers
+	 * an init sequence and hence it must be done
+	 * at the end for DDR2
+	 */
+	ldr r0, emif_addr_virt
+	add r0, r0, #EMIF_SDRAM_CONFIG
+	ldr r4, emif_sdcfg_val
+	str r4, [r0]
+
+	/*
+	 * Set SCTLR.C bit to allow data cache allocation
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	orr	r0, r0, #(1 << 2)	@ Enable the C bit
+	mcr	p15, 0, r0, c1, c0, 0
+	isb
+
+	/* Kill some time for sanity to settle in */
+	mov r0, #0x1000
+wait_abt:
+	subs   r0, r0, #1
+	bne wait_abt
+
+	/* Let the suspend code know about the abort */
+	mov	r0, #1
+	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
+ENDPROC(am33xx_do_wfi)
+
+	.align
+ENTRY(am33xx_resume_offset)
+	.word . - am33xx_do_wfi
+
+ENTRY(am33xx_resume_from_deep_sleep)
+	/* Re-enable EMIF */
+	ldr	r0, phys_emif_clkctrl
+	mov	r1, #0x02
+	str	r1, [r0]
+wait_emif_enable1:
+	ldr	r2, [r0]
+	cmp	r1, r2
+	bne	wait_emif_enable1
+
+	/* Config EMIF Timings */
+	ldr	r0, emif_phys_addr
+	ldr	r1, emif_rd_lat_val
+	str	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+	str	r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
+	ldr	r1, emif_timing1_val
+	str	r1, [r0, #EMIF_SDRAM_TIMING_1]
+	str	r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
+	ldr	r1, emif_timing2_val
+	str	r1, [r0, #EMIF_SDRAM_TIMING_2]
+	str	r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
+	ldr	r1, emif_timing3_val
+	str	r1, [r0, #EMIF_SDRAM_TIMING_3]
+	str	r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
+	ldr	r1, emif_ref_ctrl_val
+	str	r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+	str	r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
+	ldr	r1, emif_pmcr_val
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	ldr	r1, emif_pmcr_shdw_val
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+	/*
+	 * Output impedence calib needed only for DDR3
+	 * but since the initial state of this will be
+	 * disabled for DDR2 no harm in restoring the
+	 * old configuration
+	 */
+	ldr	r1, emif_zqcfg_val
+	str	r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+	/* Write to SDRAM_CONFIG only for DDR2 */
+	ldr	r2, mem_type
+	cmp	r2, #MEM_TYPE_DDR2
+	bne	resume_to_ddr
+
+	/*
+	 * A write to SDRAM CONFIG register triggers
+	 * an init sequence and hence it must be done
+	 *@the end for DDR2
+	 */
+	ldr	r1, emif_sdcfg_val
+	str	r1, [r0, #EMIF_SDRAM_CONFIG]
+
+resume_to_ddr:
+	/* Back from la-la-land. Kill some time for sanity to settle in */
+	mov	r0, #0x1000
+wait_resume:
+	subs	r0, r0, #1
+	bne	wait_resume
+
+	/* We are back. Branch to the common CPU resume routine */
+	mov	r0, #0
+	ldr	pc, resume_addr
+ENDPROC(am33xx_resume_from_deep_sleep)
+
+
+/*
+ * Local variables
+ */
+	.align
+resume_addr:
+	.word	cpu_resume - PAGE_OFFSET + 0x80000000
+kernel_flush:
+	.word   v7_flush_dcache_all
+ddr_start:
+	.word	PAGE_OFFSET
+emif_phys_addr:
+	.word	AM33XX_EMIF_BASE
+virt_mpu_clkctrl:
+	.word	AM33XX_CM_MPU_MPU_CLKCTRL
+virt_emif_clkctrl:
+	.word	AM33XX_CM_PER_EMIF_CLKCTRL
+phys_emif_clkctrl:
+	.word	(AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
+		AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)
+module_disabled_val:
+	.word	0x30000
+
+/* DDR related defines */
+dram_sync_word:
+	.word	0xDEADBEEF
+mem_type:
+	.word	0xDEADBEEF
+emif_addr_virt:
+	.word	0xDEADBEEF
+emif_rd_lat_val:
+	.word	0xDEADBEEF
+emif_timing1_val:
+	.word	0xDEADBEEF
+emif_timing2_val:
+	.word	0xDEADBEEF
+emif_timing3_val:
+	.word	0xDEADBEEF
+emif_sdcfg_val:
+	.word	0xDEADBEEF
+emif_ref_ctrl_val:
+	.word	0xDEADBEEF
+emif_zqcfg_val:
+	.word	0xDEADBEEF
+emif_pmcr_val:
+	.word	0xDEADBEEF
+emif_pmcr_shdw_val:
+	.word	0xDEADBEEF
+
+	.align 3
+ENTRY(am33xx_do_wfi_sz)
+	.word	. - am33xx_do_wfi
Signature · 1 line
1.7.9.5
#39 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

Quoted 24 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

If no interrupts have come, WFI execution on MPU gets registered as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes care of clockdomain and powerdomain transitions as part of the DeepSleep0 mode entry.

In case a late interrupt comes in, WFI ends up as a NOP and MPU continues execution from internal memory. The 'abort path' code undoes whatever was done as part of the low power entry and indicates a suspend failure by passing a non-zero value to the cpu_resume routine.

Quoted 8 lines

The 'resume path' code is similar to the 'abort path' with the key difference of MMU being enabled in the 'abort path' but being disabled in the 'resume path' due to MPU getting powered off.

Cc Santosh Shilimkar <[email protected]>
Cc Kevin Hilman <[email protected]>
Quoted 368 lines
---
 arch/arm/mach-omap2/sleep33xx.S |  350 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep33xx.S new file +350 -1
new file mode 100644
index 0000000..834c7d4
@@ -0,0 +1,350 @@
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/ti_emif.h>
+#include <asm/memory.h>
+#include <asm/assembler.h>
+
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "prm33xx.h"
+
+       .text
+       .align 3
+
+/*
+ * This routine is executed from internal RAM and expects some
+ * parameters to be passed in r0 _strictly_ in following order:
+ * 1) emif_addr_virt - ioremapped EMIF address
+ * 2) mem_type - 2 -> DDR2, 3-> DDR3
+ * 3) dram_sync_word - uncached word in SDRAM
+ *
+ * The code loads these values taking r0 value as reference to
+ * the array in registers starting from r0, i.e emif_addr_virt
+ * goes to r1, mem_type goes to r2 and and so on. These are
+ * then saved into memory locations before proceeding with the
+ * sleep sequence and hence registers r0, r1 etc can still be
+ * used in the rest of the sleep code.
+ */
+
+ENTRY(am33xx_do_wfi)
+       stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
+
+       ldm     r0, {r1-r3}             @ gather values passed
+
+       /* Save the values passed */
+       str     r1, emif_addr_virt
+       str     r2, mem_type
+       str     r3, dram_sync_word
+
+       /*
+        * Flush all data from the L1 data cache before disabling
+        * SCTLR.C bit.
+        */
+       ldr     r1, kernel_flush
+       blx     r1
+
+       /*
+        * Clear the SCTLR.C bit to prevent further data cache
+        * allocation. Clearing SCTLR.C would make all the data accesses
+        * strongly ordered and would not hit the cache.
+        */
+       mrc     p15, 0, r0, c1, c0, 0
+       bic     r0, r0, #(1 << 2)       @ Disable the C bit
+       mcr     p15, 0, r0, c1, c0, 0
+       isb
+
+       /*
+        * Invalidate L1 data cache. Even though only invalidate is
+        * necessary exported flush API is used here. Doing clean
+        * on already clean cache would be almost NOP.
+        */
+       ldr     r1, kernel_flush
+       blx     r1
+
+       ldr     r0, emif_addr_virt
+       /* Save EMIF configuration */
+       ldr     r1, [r0, #EMIF_SDRAM_CONFIG]
+       str     r1, emif_sdcfg_val
+       ldr     r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+       str     r1, emif_ref_ctrl_val
+       ldr     r1, [r0, #EMIF_SDRAM_TIMING_1]
+       str     r1, emif_timing1_val
+       ldr     r1, [r0, #EMIF_SDRAM_TIMING_2]
+       str     r1, emif_timing2_val
+       ldr     r1, [r0, #EMIF_SDRAM_TIMING_3]
+       str     r1, emif_timing3_val
+       ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+       str     r1, emif_pmcr_val
+       ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+       str     r1, emif_pmcr_shdw_val
+       ldr     r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+       str     r1, emif_zqcfg_val
+       ldr     r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+       str     r1, emif_rd_lat_val
+
+       /* Put SDRAM in self-refresh */
+       ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+       orr     r1, r1, #0xa0
+       str     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+       str     r1, [r0, #4]
+
+       ldr     r1, dram_sync_word      @ a dummy access to DDR as per spec
+       ldr     r2, [r1, #0]
+       ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+       orr     r1, r1, #0x200
+       str     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+       mov     r1, #0x1000             @ Wait for system to enter SR
+wait_sr:
+       subs    r1, r1, #1
+       bne     wait_sr
+
+       /* Disable EMIF */
+       ldr     r1, virt_emif_clkctrl
+       ldr     r2, [r1]
+       bic     r2, r2, #0x03
+       str     r2, [r1]
+
+       ldr     r1, virt_emif_clkctrl
+wait_emif_disable:
+       ldr     r2, [r1]
+       ldr     r3, module_disabled_val
+       cmp     r2, r3
+       bne     wait_emif_disable
+
+       /*
+        * For the MPU WFI to be registered as an interrupt
+        * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
+        * to DISABLED
+        */
+       ldr     r1, virt_mpu_clkctrl
+       ldr     r2, [r1]
+       bic     r2, r2, #0x03
+       str     r2, [r1]
+
+       /*
+        * Execute an ISB instruction to ensure that all of the
+        * CP15 register changes have been committed.
+        */
+       isb
+
+       /*
+        * Execute a barrier instruction to ensure that all cache,
+        * TLB and branch predictor maintenance operations issued
+        * have completed.
+        */
+       dsb
+       dmb
+
+       /*
+        * Execute a WFI instruction and wait until the
+        * STANDBYWFI output is asserted to indicate that the
+        * CPU is in idle and low power state. CPU can specualatively
+        * prefetch the instructions so add NOPs after WFI. Thirteen
+        * NOPs as per Cortex-A8 pipeline.
+        */
+       wfi
+
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
+       /* We come here in case of an abort due to a late interrupt */
+
+       /* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
+       ldr     r1, virt_mpu_clkctrl
+       mov     r2, #0x02
+       str     r2, [r1]
+
+       /* Re-enable EMIF */
+       ldr     r1, virt_emif_clkctrl
+       mov     r2, #0x02
+       str     r2, [r1]
+wait_emif_enable:
+       ldr     r3, [r1]
+       cmp     r2, r3
+       bne     wait_emif_enable
+
+       /* Disable EMIF self-refresh */
+       ldr     r0, emif_addr_virt
+       ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+       bic     r1, r1, #LP_MODE_MASK
+       str     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+       str     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+       /*
+        * A write to SDRAM CONFIG register triggers
+        * an init sequence and hence it must be done
+        * at the end for DDR2
+        */
+       ldr r0, emif_addr_virt
+       add r0, r0, #EMIF_SDRAM_CONFIG
+       ldr r4, emif_sdcfg_val
+       str r4, [r0]
+
+       /*
+        * Set SCTLR.C bit to allow data cache allocation
+        */
+       mrc     p15, 0, r0, c1, c0, 0
+       orr     r0, r0, #(1 << 2)       @ Enable the C bit
+       mcr     p15, 0, r0, c1, c0, 0
+       isb
+
+       /* Kill some time for sanity to settle in */
+       mov r0, #0x1000
+wait_abt:
+       subs   r0, r0, #1
+       bne wait_abt
+
+       /* Let the suspend code know about the abort */
+       mov     r0, #1
+       ldmfd   sp!, {r4 - r11, pc}     @ restore regs and return
+ENDPROC(am33xx_do_wfi)
+
+       .align
+ENTRY(am33xx_resume_offset)
+       .word . - am33xx_do_wfi
+
+ENTRY(am33xx_resume_from_deep_sleep)
+       /* Re-enable EMIF */
+       ldr     r0, phys_emif_clkctrl
+       mov     r1, #0x02
+       str     r1, [r0]
+wait_emif_enable1:
+       ldr     r2, [r0]
+       cmp     r1, r2
+       bne     wait_emif_enable1
+
+       /* Config EMIF Timings */
+       ldr     r0, emif_phys_addr
+       ldr     r1, emif_rd_lat_val
+       str     r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+       str     r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
+       ldr     r1, emif_timing1_val
+       str     r1, [r0, #EMIF_SDRAM_TIMING_1]
+       str     r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
+       ldr     r1, emif_timing2_val
+       str     r1, [r0, #EMIF_SDRAM_TIMING_2]
+       str     r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
+       ldr     r1, emif_timing3_val
+       str     r1, [r0, #EMIF_SDRAM_TIMING_3]
+       str     r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
+       ldr     r1, emif_ref_ctrl_val
+       str     r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+       str     r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
+       ldr     r1, emif_pmcr_val
+       str     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+       ldr     r1, emif_pmcr_shdw_val
+       str     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+       /*
+        * Output impedence calib needed only for DDR3
+        * but since the initial state of this will be
+        * disabled for DDR2 no harm in restoring the
+        * old configuration
+        */
+       ldr     r1, emif_zqcfg_val
+       str     r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+       /* Write to SDRAM_CONFIG only for DDR2 */
+       ldr     r2, mem_type
+       cmp     r2, #MEM_TYPE_DDR2
+       bne     resume_to_ddr
+
+       /*
+        * A write to SDRAM CONFIG register triggers
+        * an init sequence and hence it must be done
+        * at the end for DDR2
+        */
+       ldr     r1, emif_sdcfg_val
+       str     r1, [r0, #EMIF_SDRAM_CONFIG]
+
+resume_to_ddr:
+       /* Back from la-la-land. Kill some time for sanity to settle in */
+       mov     r0, #0x1000
+wait_resume:
+       subs    r0, r0, #1
+       bne     wait_resume
+
+       /* We are back. Branch to the common CPU resume routine */
+       mov     r0, #0
+       ldr     pc, resume_addr
+ENDPROC(am33xx_resume_from_deep_sleep)
+
+
+/*
+ * Local variables
+ */
+       .align
+resume_addr:
+       .word   cpu_resume - PAGE_OFFSET + 0x80000000
+kernel_flush:
+       .word   v7_flush_dcache_all
+ddr_start:
+       .word   PAGE_OFFSET
+emif_phys_addr:
+       .word   AM33XX_EMIF_BASE
+virt_mpu_clkctrl:
+       .word   AM33XX_CM_MPU_MPU_CLKCTRL
+virt_emif_clkctrl:
+       .word   AM33XX_CM_PER_EMIF_CLKCTRL
+phys_emif_clkctrl:
+       .word   (AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
+               AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)
+module_disabled_val:
+       .word   0x30000
+
+/* DDR related defines */
+dram_sync_word:
+       .word   0xDEADBEEF
+mem_type:
+       .word   0xDEADBEEF
+emif_addr_virt:
+       .word   0xDEADBEEF
+emif_rd_lat_val:
+       .word   0xDEADBEEF
+emif_timing1_val:
+       .word   0xDEADBEEF
+emif_timing2_val:
+       .word   0xDEADBEEF
+emif_timing3_val:
+       .word   0xDEADBEEF
+emif_sdcfg_val:
+       .word   0xDEADBEEF
+emif_ref_ctrl_val:
+       .word   0xDEADBEEF
+emif_zqcfg_val:
+       .word   0xDEADBEEF
+emif_pmcr_val:
+       .word   0xDEADBEEF
+emif_pmcr_shdw_val:
+       .word   0xDEADBEEF
+
+       .align 3
+ENTRY(am33xx_do_wfi_sz)
+       .word   . - am33xx_do_wfi
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#40 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

In reply to Dave Gerlach
Quoted 85 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

If no interrupts have come, WFI execution on MPU gets registered as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes care of clockdomain and powerdomain transitions as part of the DeepSleep0 mode entry.

In case a late interrupt comes in, WFI ends up as a NOP and MPU continues execution from internal memory. The 'abort path' code undoes whatever was done as part of the low power entry and indicates a suspend failure by passing a non-zero value to the cpu_resume routine.

The 'resume path' code is similar to the 'abort path' with the key difference of MMU being enabled in the 'abort path' but being disabled in the 'resume path' due to MPU getting powered off.

Cc Santosh Shilimkar <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/sleep33xx.S |  350 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep33xx.S new file +42 -0
new file mode 100644
index 0000000..834c7d4
@@ -0,0 +1,350 @@
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/ti_emif.h>
+#include <asm/memory.h>
+#include <asm/assembler.h>
+
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "prm33xx.h"
+
+	.text
+	.align 3
+
+/*
+ * This routine is executed from internal RAM and expects some
+ * parameters to be passed in r0 _strictly_ in following order:
+ * 1) emif_addr_virt - ioremapped EMIF address
+ * 2) mem_type - 2 -> DDR2, 3-> DDR3
+ * 3) dram_sync_word - uncached word in SDRAM
+ *
+ * The code loads these values taking r0 value as reference to
+ * the array in registers starting from r0, i.e emif_addr_virt
+ * goes to r1, mem_type goes to r2 and and so on. These are
+ * then saved into memory locations before proceeding with the
+ * sleep sequence and hence registers r0, r1 etc can still be
+ * used in the rest of the sleep code.
+ */

arch/arm/mach-omap2/sleep33xx.S line 52

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+
+ENTRY(am33xx_do_wfi)
+	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
+
+	ldm	r0, {r1-r3}		@ gather values passed
+
+	/* Save the values passed */
+	str	r1, emif_addr_virt
+	str	r2, mem_type
+	str	r3, dram_sync_word

None of this parameter are going to change for every suspend entry and exit so saving them once and accessing them should be fine. Just create a structure with above, save them in init from C code and then access that structure where you need to.

Quoted 13 lines
arch/arm/mach-omap2/sleep33xx.S new file +13 -0
+
+	/*
+	 * Flush all data from the L1 data cache before disabling
+	 * SCTLR.C bit.
+	 */
+	ldr	r1, kernel_flush
+	blx	r1
+
+	/*
+	 * Clear the SCTLR.C bit to prevent further data cache
+	 * allocation. Clearing SCTLR.C would make all the data accesses
+	 * strongly ordered and would not hit the cache.
+	 */

arch/arm/mach-omap2/sleep33xx.S line 75

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #(1 << 2)	@ Disable the C bit
+	mcr	p15, 0, r0, c1, c0, 0
+	isb
+
+	/*
+	 * Invalidate L1 data cache. Even though only invalidate is
+	 * necessary exported flush API is used here. Doing clean
+	 * on already clean cache would be almost NOP.
+	 */

Comment is stale for AM33XX since below flush will clean l1 and l2 together. We need to first flush and then invalidate. Please update it.

Quoted 17 lines
arch/arm/mach-omap2/sleep33xx.S new file +17 -0
+	ldr	r1, kernel_flush
+	blx	r1
+
+	ldr	r0, emif_addr_virt
+	/* Save EMIF configuration */
+	ldr	r1, [r0, #EMIF_SDRAM_CONFIG]
+	str	r1, emif_sdcfg_val
+	ldr	r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+	str	r1, emif_ref_ctrl_val
+	ldr	r1, [r0, #EMIF_SDRAM_TIMING_1]
+	str	r1, emif_timing1_val
+	ldr	r1, [r0, #EMIF_SDRAM_TIMING_2]
+	str	r1, emif_timing2_val
+	ldr	r1, [r0, #EMIF_SDRAM_TIMING_3]
+	str	r1, emif_timing3_val
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	str	r1, emif_pmcr_val

arch/arm/mach-omap2/sleep33xx.S line 102

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+	str	r1, emif_pmcr_shdw_val
+	ldr	r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+	str	r1, emif_zqcfg_val
+	ldr	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+	str	r1, emif_rd_lat_val
+
+	/* Put SDRAM in self-refresh */
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	orr	r1, r1, #0xa0

No magic numbers please. here and rest of the patch. Have proper defines.

arch/arm/mach-omap2/sleep33xx.S line 113

Quoted 11 lines
arch/arm/mach-omap2/sleep33xx.S new file +11 -0
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+	str	r1, [r0, #4]
+
+	ldr	r1, dram_sync_word	@ a dummy access to DDR as per spec
+	ldr	r2, [r1, #0]
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	orr	r1, r1, #0x200
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+	mov	r1, #0x1000		@ Wait for system to enter SR
+wait_sr:

What is sr ? I know you mean self-refresh, but sr can be smart reflex as well. Fix that please.

arch/arm/mach-omap2/sleep33xx.S line 116

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+	subs	r1, r1, #1
+	bne	wait_sr
+

So how did you derive this 0x1000 number. Whats the real delay need ? For e.g a CPU running at 600 MHz vs running at 1.2 GHz, the above loop becomes 2 times faster.

Quoted 11 lines
arch/arm/mach-omap2/sleep33xx.S new file +11 -0
+	/* Disable EMIF */
+	ldr	r1, virt_emif_clkctrl
+	ldr	r2, [r1]
+	bic	r2, r2, #0x03
+	str	r2, [r1]
+
+	ldr	r1, virt_emif_clkctrl
+wait_emif_disable:
+	ldr	r2, [r1]
+	ldr	r3, module_disabled_val
+	cmp	r2, r3

arch/arm/mach-omap2/sleep33xx.S line 137

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+	bne	wait_emif_disable
+
+	/*
+	 * For the MPU WFI to be registered as an interrupt
+	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
+	 * to DISABLED
+	 */
+	ldr	r1, virt_mpu_clkctrl
+	ldr	r2, [r1]
+	bic	r2, r2, #0x03

Magic value

Quoted 71 lines
arch/arm/mach-omap2/sleep33xx.S new file +71 -0
+	str	r2, [r1]
+
+	/*
+	 * Execute an ISB instruction to ensure that all of the
+	 * CP15 register changes have been committed.
+	 */
+	isb
+
+	/*
+	 * Execute a barrier instruction to ensure that all cache,
+	 * TLB and branch predictor maintenance operations issued
+	 * have completed.
+	 */
+	dsb
+	dmb
+
+	/*
+	 * Execute a WFI instruction and wait until the
+	 * STANDBYWFI output is asserted to indicate that the
+	 * CPU is in idle and low power state. CPU can specualatively
+	 * prefetch the instructions so add NOPs after WFI. Thirteen
+	 * NOPs as per Cortex-A8 pipeline.
+	 */
+	wfi
+
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	/* We come here in case of an abort due to a late interrupt */
+
+	/* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
+	ldr	r1, virt_mpu_clkctrl
+	mov	r2, #0x02
+	str	r2, [r1]
+
+	/* Re-enable EMIF */
+	ldr	r1, virt_emif_clkctrl
+	mov	r2, #0x02
+	str	r2, [r1]
+wait_emif_enable:
+	ldr	r3, [r1]
+	cmp	r2, r3
+	bne	wait_emif_enable
+
+	/* Disable EMIF self-refresh */
+	ldr	r0, emif_addr_virt
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	bic	r1, r1, #LP_MODE_MASK
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+	/*
+	 * A write to SDRAM CONFIG register triggers
+	 * an init sequence and hence it must be done
+	 * at the end for DDR2
+	 */
+	ldr r0, emif_addr_virt
+	add r0, r0, #EMIF_SDRAM_CONFIG
+	ldr r4, emif_sdcfg_val
+	str r4, [r0]

arch/arm/mach-omap2/sleep33xx.S line 218

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+
+	/*
+	 * Set SCTLR.C bit to allow data cache allocation
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	orr	r0, r0, #(1 << 2)	@ Enable the C bit
+	mcr	p15, 0, r0, c1, c0, 0
+	isb
+
+	/* Kill some time for sanity to settle in */

Really ?

arch/arm/mach-omap2/sleep33xx.S line 222

Quoted 4 lines
arch/arm/mach-omap2/sleep33xx.S new file +4 -0
+	mov r0, #0x1000
+wait_abt:
+	subs   r0, r0, #1
+	bne wait_abt

Why do you want to kill time ? How
does this 0x1000 delay sanities it.

Quoted 61 lines
arch/arm/mach-omap2/sleep33xx.S new file +61 -0
+
+	/* Let the suspend code know about the abort */
+	mov	r0, #1
+	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
+ENDPROC(am33xx_do_wfi)
+
+	.align
+ENTRY(am33xx_resume_offset)
+	.word . - am33xx_do_wfi
+
+ENTRY(am33xx_resume_from_deep_sleep)
+	/* Re-enable EMIF */
+	ldr	r0, phys_emif_clkctrl
+	mov	r1, #0x02
+	str	r1, [r0]
+wait_emif_enable1:
+	ldr	r2, [r0]
+	cmp	r1, r2
+	bne	wait_emif_enable1
+
+	/* Config EMIF Timings */
+	ldr	r0, emif_phys_addr
+	ldr	r1, emif_rd_lat_val
+	str	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+	str	r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
+	ldr	r1, emif_timing1_val
+	str	r1, [r0, #EMIF_SDRAM_TIMING_1]
+	str	r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
+	ldr	r1, emif_timing2_val
+	str	r1, [r0, #EMIF_SDRAM_TIMING_2]
+	str	r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
+	ldr	r1, emif_timing3_val
+	str	r1, [r0, #EMIF_SDRAM_TIMING_3]
+	str	r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
+	ldr	r1, emif_ref_ctrl_val
+	str	r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+	str	r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
+	ldr	r1, emif_pmcr_val
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	ldr	r1, emif_pmcr_shdw_val
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+	/*
+	 * Output impedence calib needed only for DDR3
+	 * but since the initial state of this will be
+	 * disabled for DDR2 no harm in restoring the
+	 * old configuration
+	 */
+	ldr	r1, emif_zqcfg_val
+	str	r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+	/* Write to SDRAM_CONFIG only for DDR2 */
+	ldr	r2, mem_type
+	cmp	r2, #MEM_TYPE_DDR2
+	bne	resume_to_ddr
+
+	/*
+	 * A write to SDRAM CONFIG register triggers
+	 * an init sequence and hence it must be done
+	 * at the end for DDR2
+	 */

arch/arm/mach-omap2/sleep33xx.S line 293

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+	ldr	r1, emif_sdcfg_val
+	str	r1, [r0, #EMIF_SDRAM_CONFIG]
+
+resume_to_ddr:
+	/* Back from la-la-land. Kill some time for sanity to settle in */
+	mov	r0, #0x1000
+wait_resume:
+	subs	r0, r0, #1
+	bne	wait_resume
+

You are killing too much time ;-)
without mentioning why ?

arch/arm/mach-omap2/sleep33xx.S line 296

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+	/* We are back. Branch to the common CPU resume routine */
+	mov	r0, #0
+	ldr	pc, resume_addr

Why can't you resume to "cpu_resume" directly.

arch/arm/mach-omap2/sleep33xx.S line 305

Quoted 9 lines
arch/arm/mach-omap2/sleep33xx.S new file +9 -0
+ENDPROC(am33xx_resume_from_deep_sleep)
+
+
+/*
+ * Local variables
+ */
+	.align
+resume_addr:
+	.word	cpu_resume - PAGE_OFFSET + 0x80000000

Do you really need above math ?

Quoted 32 lines
arch/arm/mach-omap2/sleep33xx.S new file +32 -0
+kernel_flush:
+	.word   v7_flush_dcache_all
+ddr_start:
+	.word	PAGE_OFFSET
+emif_phys_addr:
+	.word	AM33XX_EMIF_BASE
+virt_mpu_clkctrl:
+	.word	AM33XX_CM_MPU_MPU_CLKCTRL
+virt_emif_clkctrl:
+	.word	AM33XX_CM_PER_EMIF_CLKCTRL
+phys_emif_clkctrl:
+	.word	(AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
+		AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)
+module_disabled_val:
+	.word	0x30000
+
+/* DDR related defines */
+dram_sync_word:
+	.word	0xDEADBEEF
+mem_type:
+	.word	0xDEADBEEF
+emif_addr_virt:
+	.word	0xDEADBEEF
+emif_rd_lat_val:
+	.word	0xDEADBEEF
+emif_timing1_val:
+	.word	0xDEADBEEF
+emif_timing2_val:
+	.word	0xDEADBEEF
+emif_timing3_val:
+	.word	0xDEADBEEF
+emif_sdcfg_val:

arch/arm/mach-omap2/sleep33xx.S line 347

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+	.word	0xDEADBEEF
+emif_ref_ctrl_val:
+	.word	0xDEADBEEF
+emif_zqcfg_val:
+	.word	0xDEADBEEF
+emif_pmcr_val:
+	.word	0xDEADBEEF
+emif_pmcr_shdw_val:
+	.word	0xDEADBEEF
+

You can create a structure above above regs.
refer 'cache-l2x0.h' struct l2x0_regs in case
you need an example.

Looks like you don't care about secure devices ?
Just confirm it.

Regards,
Santosh

#41 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

Quoted 93 lines · Santosh Shilimkar
Quoted 92 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

If no interrupts have come, WFI execution on MPU gets registered as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes care of clockdomain and powerdomain transitions as part of the DeepSleep0 mode entry.

In case a late interrupt comes in, WFI ends up as a NOP and MPU continues execution from internal memory. The 'abort path' code undoes whatever was done as part of the low power entry and indicates a suspend failure by passing a non-zero value to the cpu_resume routine.

The 'resume path' code is similar to the 'abort path' with the key difference of MMU being enabled in the 'abort path' but being disabled in the 'resume path' due to MPU getting powered off.

Cc Santosh Shilimkar <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/sleep33xx.S |  350 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep33xx.S new file +49 -0
new file mode 100644
index 0000000..834c7d4
@@ -0,0 +1,350 @@
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/ti_emif.h>
+#include <asm/memory.h>
+#include <asm/assembler.h>
+
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "prm33xx.h"
+
+     .text
+     .align 3
+
+/*
+ * This routine is executed from internal RAM and expects some
+ * parameters to be passed in r0 _strictly_ in following order:
+ * 1) emif_addr_virt - ioremapped EMIF address
+ * 2) mem_type - 2 -> DDR2, 3-> DDR3
+ * 3) dram_sync_word - uncached word in SDRAM
+ *
+ * The code loads these values taking r0 value as reference to
+ * the array in registers starting from r0, i.e emif_addr_virt
+ * goes to r1, mem_type goes to r2 and and so on. These are
+ * then saved into memory locations before proceeding with the
+ * sleep sequence and hence registers r0, r1 etc can still be
+ * used in the rest of the sleep code.
+ */
+
+ENTRY(am33xx_do_wfi)
+     stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
+
+     ldm     r0, {r1-r3}             @ gather values passed
+
+     /* Save the values passed */
Quoted 8 lines

arch/arm/mach-omap2/sleep33xx.S line 52

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+     str     r1, emif_addr_virt
+     str     r2, mem_type
+     str     r3, dram_sync_word

None of this parameter are going to change for every suspend entry and exit so saving them once and accessing them should be fine. Just create a structure with above, save them in init from C code and then access that structure where you need to.

It isn't possible to do so since the structure would be in SDRAM and at resume time, we don't have access to SDRAM. Additionally, I'd like to expand the mem_type parameter to a bit field in the future to allow this code path to be shared with CPU idle.

Quoted 333 lines
Quoted 13 lines
arch/arm/mach-omap2/sleep33xx.S new file +13 -0
+
+     /*
+      * Flush all data from the L1 data cache before disabling
+      * SCTLR.C bit.
+      */
+     ldr     r1, kernel_flush
+     blx     r1
+
+     /*
+      * Clear the SCTLR.C bit to prevent further data cache
+      * allocation. Clearing SCTLR.C would make all the data accesses
+      * strongly ordered and would not hit the cache.
+      */

arch/arm/mach-omap2/sleep33xx.S line 75

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+     mrc     p15, 0, r0, c1, c0, 0
+     bic     r0, r0, #(1 << 2)       @ Disable the C bit
+     mcr     p15, 0, r0, c1, c0, 0
+     isb
+
+     /*
+      * Invalidate L1 data cache. Even though only invalidate is
+      * necessary exported flush API is used here. Doing clean
+      * on already clean cache would be almost NOP.
+      */

Comment is stale for AM33XX since below flush will clean l1 and l2 together. We need to first flush and then invalidate. Please update it.

Quoted 17 lines
arch/arm/mach-omap2/sleep33xx.S new file +17 -0
+     ldr     r1, kernel_flush
+     blx     r1
+
+     ldr     r0, emif_addr_virt
+     /* Save EMIF configuration */
+     ldr     r1, [r0, #EMIF_SDRAM_CONFIG]
+     str     r1, emif_sdcfg_val
+     ldr     r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+     str     r1, emif_ref_ctrl_val
+     ldr     r1, [r0, #EMIF_SDRAM_TIMING_1]
+     str     r1, emif_timing1_val
+     ldr     r1, [r0, #EMIF_SDRAM_TIMING_2]
+     str     r1, emif_timing2_val
+     ldr     r1, [r0, #EMIF_SDRAM_TIMING_3]
+     str     r1, emif_timing3_val
+     ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+     str     r1, emif_pmcr_val

arch/arm/mach-omap2/sleep33xx.S line 102

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+     ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+     str     r1, emif_pmcr_shdw_val
+     ldr     r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+     str     r1, emif_zqcfg_val
+     ldr     r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+     str     r1, emif_rd_lat_val
+
+     /* Put SDRAM in self-refresh */
+     ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+     orr     r1, r1, #0xa0

No magic numbers please. here and rest of the patch. Have proper defines.

arch/arm/mach-omap2/sleep33xx.S line 113

Quoted 11 lines
arch/arm/mach-omap2/sleep33xx.S new file +11 -0
+     str     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+     str     r1, [r0, #4]
+
+     ldr     r1, dram_sync_word      @ a dummy access to DDR as per spec
+     ldr     r2, [r1, #0]
+     ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+     orr     r1, r1, #0x200
+     str     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+
+     mov     r1, #0x1000             @ Wait for system to enter SR
+wait_sr:

What is sr ? I know you mean self-refresh, but sr can be smart reflex as well. Fix that please.

arch/arm/mach-omap2/sleep33xx.S line 116

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+     subs    r1, r1, #1
+     bne     wait_sr
+

So how did you derive this 0x1000 number. Whats the real delay need ? For e.g a CPU running at 600 MHz vs running at 1.2 GHz, the above loop becomes 2 times faster.

Quoted 11 lines
arch/arm/mach-omap2/sleep33xx.S new file +11 -0
+     /* Disable EMIF */
+     ldr     r1, virt_emif_clkctrl
+     ldr     r2, [r1]
+     bic     r2, r2, #0x03
+     str     r2, [r1]
+
+     ldr     r1, virt_emif_clkctrl
+wait_emif_disable:
+     ldr     r2, [r1]
+     ldr     r3, module_disabled_val
+     cmp     r2, r3

arch/arm/mach-omap2/sleep33xx.S line 137

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+     bne     wait_emif_disable
+
+     /*
+      * For the MPU WFI to be registered as an interrupt
+      * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
+      * to DISABLED
+      */
+     ldr     r1, virt_mpu_clkctrl
+     ldr     r2, [r1]
+     bic     r2, r2, #0x03

Magic value

Quoted 71 lines
arch/arm/mach-omap2/sleep33xx.S new file +71 -0
+     str     r2, [r1]
+
+     /*
+      * Execute an ISB instruction to ensure that all of the
+      * CP15 register changes have been committed.
+      */
+     isb
+
+     /*
+      * Execute a barrier instruction to ensure that all cache,
+      * TLB and branch predictor maintenance operations issued
+      * have completed.
+      */
+     dsb
+     dmb
+
+     /*
+      * Execute a WFI instruction and wait until the
+      * STANDBYWFI output is asserted to indicate that the
+      * CPU is in idle and low power state. CPU can specualatively
+      * prefetch the instructions so add NOPs after WFI. Thirteen
+      * NOPs as per Cortex-A8 pipeline.
+      */
+     wfi
+
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+     nop
+
+     /* We come here in case of an abort due to a late interrupt */
+
+     /* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
+     ldr     r1, virt_mpu_clkctrl
+     mov     r2, #0x02
+     str     r2, [r1]
+
+     /* Re-enable EMIF */
+     ldr     r1, virt_emif_clkctrl
+     mov     r2, #0x02
+     str     r2, [r1]
+wait_emif_enable:
+     ldr     r3, [r1]
+     cmp     r2, r3
+     bne     wait_emif_enable
+
+     /* Disable EMIF self-refresh */
+     ldr     r0, emif_addr_virt
+     ldr     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+     bic     r1, r1, #LP_MODE_MASK
+     str     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+     str     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+     /*
+      * A write to SDRAM CONFIG register triggers
+      * an init sequence and hence it must be done
+      * at the end for DDR2
+      */
+     ldr r0, emif_addr_virt
+     add r0, r0, #EMIF_SDRAM_CONFIG
+     ldr r4, emif_sdcfg_val
+     str r4, [r0]

arch/arm/mach-omap2/sleep33xx.S line 218

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+
+     /*
+      * Set SCTLR.C bit to allow data cache allocation
+      */
+     mrc     p15, 0, r0, c1, c0, 0
+     orr     r0, r0, #(1 << 2)       @ Enable the C bit
+     mcr     p15, 0, r0, c1, c0, 0
+     isb
+
+     /* Kill some time for sanity to settle in */

Really ?

arch/arm/mach-omap2/sleep33xx.S line 222

Quoted 4 lines
arch/arm/mach-omap2/sleep33xx.S new file +4 -0
+     mov r0, #0x1000
+wait_abt:
+     subs   r0, r0, #1
+     bne wait_abt

Why do you want to kill time ? How
does this 0x1000 delay sanities it.

Quoted 61 lines
arch/arm/mach-omap2/sleep33xx.S new file +61 -0
+
+     /* Let the suspend code know about the abort */
+     mov     r0, #1
+     ldmfd   sp!, {r4 - r11, pc}     @ restore regs and return
+ENDPROC(am33xx_do_wfi)
+
+     .align
+ENTRY(am33xx_resume_offset)
+     .word . - am33xx_do_wfi
+
+ENTRY(am33xx_resume_from_deep_sleep)
+     /* Re-enable EMIF */
+     ldr     r0, phys_emif_clkctrl
+     mov     r1, #0x02
+     str     r1, [r0]
+wait_emif_enable1:
+     ldr     r2, [r0]
+     cmp     r1, r2
+     bne     wait_emif_enable1
+
+     /* Config EMIF Timings */
+     ldr     r0, emif_phys_addr
+     ldr     r1, emif_rd_lat_val
+     str     r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+     str     r1, [r0, #EMIF_DDR_PHY_CTRL_1_SHDW]
+     ldr     r1, emif_timing1_val
+     str     r1, [r0, #EMIF_SDRAM_TIMING_1]
+     str     r1, [r0, #EMIF_SDRAM_TIMING_1_SHDW]
+     ldr     r1, emif_timing2_val
+     str     r1, [r0, #EMIF_SDRAM_TIMING_2]
+     str     r1, [r0, #EMIF_SDRAM_TIMING_2_SHDW]
+     ldr     r1, emif_timing3_val
+     str     r1, [r0, #EMIF_SDRAM_TIMING_3]
+     str     r1, [r0, #EMIF_SDRAM_TIMING_3_SHDW]
+     ldr     r1, emif_ref_ctrl_val
+     str     r1, [r0, #EMIF_SDRAM_REFRESH_CONTROL]
+     str     r1, [r0, #EMIF_SDRAM_REFRESH_CTRL_SHDW]
+     ldr     r1, emif_pmcr_val
+     str     r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+     ldr     r1, emif_pmcr_shdw_val
+     str     r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+
+     /*
+      * Output impedence calib needed only for DDR3
+      * but since the initial state of this will be
+      * disabled for DDR2 no harm in restoring the
+      * old configuration
+      */
+     ldr     r1, emif_zqcfg_val
+     str     r1, [r0, #EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG]
+
+     /* Write to SDRAM_CONFIG only for DDR2 */
+     ldr     r2, mem_type
+     cmp     r2, #MEM_TYPE_DDR2
+     bne     resume_to_ddr
+
+     /*
+      * A write to SDRAM CONFIG register triggers
+      * an init sequence and hence it must be done
+      * at the end for DDR2
+      */

arch/arm/mach-omap2/sleep33xx.S line 293

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+     ldr     r1, emif_sdcfg_val
+     str     r1, [r0, #EMIF_SDRAM_CONFIG]
+
+resume_to_ddr:
+     /* Back from la-la-land. Kill some time for sanity to settle in */
+     mov     r0, #0x1000
+wait_resume:
+     subs    r0, r0, #1
+     bne     wait_resume
+

You are killing too much time ;-)
without mentioning why ?

arch/arm/mach-omap2/sleep33xx.S line 296

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+     /* We are back. Branch to the common CPU resume routine */
+     mov     r0, #0
+     ldr     pc, resume_addr

Why can't you resume to "cpu_resume" directly.

arch/arm/mach-omap2/sleep33xx.S line 305

Quoted 9 lines
arch/arm/mach-omap2/sleep33xx.S new file +9 -0
+ENDPROC(am33xx_resume_from_deep_sleep)
+
+
+/*
+ * Local variables
+ */
+     .align
+resume_addr:
+     .word   cpu_resume - PAGE_OFFSET + 0x80000000

Do you really need above math ?

Quoted 32 lines
arch/arm/mach-omap2/sleep33xx.S new file +32 -0
+kernel_flush:
+     .word   v7_flush_dcache_all
+ddr_start:
+     .word   PAGE_OFFSET
+emif_phys_addr:
+     .word   AM33XX_EMIF_BASE
+virt_mpu_clkctrl:
+     .word   AM33XX_CM_MPU_MPU_CLKCTRL
+virt_emif_clkctrl:
+     .word   AM33XX_CM_PER_EMIF_CLKCTRL
+phys_emif_clkctrl:
+     .word   (AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
+             AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)
+module_disabled_val:
+     .word   0x30000
+
+/* DDR related defines */
+dram_sync_word:
+     .word   0xDEADBEEF
+mem_type:
+     .word   0xDEADBEEF
+emif_addr_virt:
+     .word   0xDEADBEEF
+emif_rd_lat_val:
+     .word   0xDEADBEEF
+emif_timing1_val:
+     .word   0xDEADBEEF
+emif_timing2_val:
+     .word   0xDEADBEEF
+emif_timing3_val:
+     .word   0xDEADBEEF
+emif_sdcfg_val:

arch/arm/mach-omap2/sleep33xx.S line 347

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+     .word   0xDEADBEEF
+emif_ref_ctrl_val:
+     .word   0xDEADBEEF
+emif_zqcfg_val:
+     .word   0xDEADBEEF
+emif_pmcr_val:
+     .word   0xDEADBEEF
+emif_pmcr_shdw_val:
+     .word   0xDEADBEEF
+

You can create a structure above above regs.
refer 'cache-l2x0.h' struct l2x0_regs in case
you need an example.

Looks like you don't care about secure devices ?
Just confirm it.

Regards,
Santosh

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#42 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

Quoted 104 lines · Russ Dill
Quoted 93 lines · Santosh Shilimkar
Quoted 92 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

If no interrupts have come, WFI execution on MPU gets registered as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes care of clockdomain and powerdomain transitions as part of the DeepSleep0 mode entry.

In case a late interrupt comes in, WFI ends up as a NOP and MPU continues execution from internal memory. The 'abort path' code undoes whatever was done as part of the low power entry and indicates a suspend failure by passing a non-zero value to the cpu_resume routine.

The 'resume path' code is similar to the 'abort path' with the key difference of MMU being enabled in the 'abort path' but being disabled in the 'resume path' due to MPU getting powered off.

Cc Santosh Shilimkar <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/sleep33xx.S |  350 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep33xx.S new file +49 -0
new file mode 100644
index 0000000..834c7d4
@@ -0,0 +1,350 @@
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/ti_emif.h>
+#include <asm/memory.h>
+#include <asm/assembler.h>
+
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "prm33xx.h"
+
+     .text
+     .align 3
+
+/*
+ * This routine is executed from internal RAM and expects some
+ * parameters to be passed in r0 _strictly_ in following order:
+ * 1) emif_addr_virt - ioremapped EMIF address
+ * 2) mem_type - 2 -> DDR2, 3-> DDR3
+ * 3) dram_sync_word - uncached word in SDRAM
+ *
+ * The code loads these values taking r0 value as reference to
+ * the array in registers starting from r0, i.e emif_addr_virt
+ * goes to r1, mem_type goes to r2 and and so on. These are
+ * then saved into memory locations before proceeding with the
+ * sleep sequence and hence registers r0, r1 etc can still be
+ * used in the rest of the sleep code.
+ */
+
+ENTRY(am33xx_do_wfi)
+     stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
+
+     ldm     r0, {r1-r3}             @ gather values passed
+
+     /* Save the values passed */
Quoted 8 lines

arch/arm/mach-omap2/sleep33xx.S line 52

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+     str     r1, emif_addr_virt
+     str     r2, mem_type
+     str     r3, dram_sync_word

None of this parameter are going to change for every suspend entry and exit so saving them once and accessing them should be fine. Just create a structure with above, save them in init from C code and then access that structure where you need to.

Quoted 5 lines

It isn't possible to do so since the structure would be in SDRAM and at resume time, we don't have access to SDRAM. Additionally, I'd like to expand the mem_type parameter to a bit field in the future to allow this code path to be shared with CPU idle.

You can copy the structure in SRAM. So how does memtype need changes for CPUIDLE ?

I have several comments on this patch so I assume you are going to address them then.

Regards,
Santosh

#43 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

Quoted 105 lines · Santosh Shilimkar
Quoted 104 lines · Russ Dill
Quoted 101 lines · Santosh Shilimkar
Quoted 85 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

If no interrupts have come, WFI execution on MPU gets registered as an interrupt with the WKUP-M3. WKUP-M3 takes care of disabling some clocks which MPU should not (L3, L4, OCMC RAM etc) and takes care of clockdomain and powerdomain transitions as part of the DeepSleep0 mode entry.

In case a late interrupt comes in, WFI ends up as a NOP and MPU continues execution from internal memory. The 'abort path' code undoes whatever was done as part of the low power entry and indicates a suspend failure by passing a non-zero value to the cpu_resume routine.

The 'resume path' code is similar to the 'abort path' with the key difference of MMU being enabled in the 'abort path' but being disabled in the 'resume path' due to MPU getting powered off.

Cc Santosh Shilimkar <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/sleep33xx.S |  350 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 350 insertions(+)
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
arch/arm/mach-omap2/sleep33xx.S new file +42 -0
new file mode 100644
index 0000000..834c7d4
@@ -0,0 +1,350 @@
+/*
+ * Low level suspend code for AM33XX SoCs
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <linux/ti_emif.h>
+#include <asm/memory.h>
+#include <asm/assembler.h>
+
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "prm33xx.h"
+
+     .text
+     .align 3
+
+/*
+ * This routine is executed from internal RAM and expects some
+ * parameters to be passed in r0 _strictly_ in following order:
+ * 1) emif_addr_virt - ioremapped EMIF address
+ * 2) mem_type - 2 -> DDR2, 3-> DDR3
+ * 3) dram_sync_word - uncached word in SDRAM
+ *
+ * The code loads these values taking r0 value as reference to
+ * the array in registers starting from r0, i.e emif_addr_virt
+ * goes to r1, mem_type goes to r2 and and so on. These are
+ * then saved into memory locations before proceeding with the
+ * sleep sequence and hence registers r0, r1 etc can still be
+ * used in the rest of the sleep code.
+ */

arch/arm/mach-omap2/sleep33xx.S line 52

Quoted 10 lines
arch/arm/mach-omap2/sleep33xx.S new file +10 -0
+
+ENTRY(am33xx_do_wfi)
+     stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
+
+     ldm     r0, {r1-r3}             @ gather values passed
+
+     /* Save the values passed */
+     str     r1, emif_addr_virt
+     str     r2, mem_type
+     str     r3, dram_sync_word

None of this parameter are going to change for every suspend entry and exit so saving them once and accessing them should be fine. Just create a structure with above, save them in init from C code and then access that structure where you need to.

Quoted 7 lines
Quoted 5 lines

It isn't possible to do so since the structure would be in SDRAM and at resume time, we don't have access to SDRAM. Additionally, I'd like to expand the mem_type parameter to a bit field in the future to allow this code path to be shared with CPU idle.

You can copy the structure in SRAM. So how does memtype need changes for CPUIDLE ?

You'd have to reserve the address and have a symbol exported for it, then after pushing everything to SRAM, you'd have to calculate the pushed address of the reserved space, then do a memcpy. It'd be a bit convoluted. Passing the address to the struct into tho wfi function is really easy and a pretty common thing to do.

For cpuidle, i'd probably change it to a flags field instead of just memtype. For instance ddr2 would be (1 << 0), and ddr3 would (1 << 1). Other flags could then be added, such as whether or not to notify the M3@WFI time.

Quoted 7 lines

I have several comments on this patch so I assume you are going to address them then.

Regards,
Santosh

#44 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

In reply to Dave Gerlach

Hi,

Quoted 13 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

...snip...
...snip...

arch/arm/mach-omap2/sleep33xx.S line 104

Quoted 8 lines
arch/arm/mach-omap2/sleep33xx.S new file +8 -0
+	ldr	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+	str	r1, emif_rd_lat_val
+
+	/* Put SDRAM in self-refresh */
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	orr	r1, r1, #0xa0
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+	str	r1, [r0, #4]

This seems to be a bug which I had pointed out to VB earlier.

r0 ---> base of emif module

r0 + 4 ---> EMIF4_0_SDRAM_STATUS ===> which is read only register

Above 2 lines should be as below

+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+ str r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]

It works even with the bug because the Shadow register is updated and that some how seems to take precedence.

Thanks & regards
Gururaja

Quoted 3 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+
+	ldr	r1, dram_sync_word	@ a dummy access to DDR as per spec
+	ldr	r2, [r1, #0]
#45 lore raw

PATCH v3 5/9 ARM: OMAP2+: AM33XX: Add assembly code for PM operations

Quoted 43 lines · Gururaja Hebbar

Hi,

Quoted 13 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

In preparation for suspend-resume support for AM33XX, add the assembly file with the code which is copied to internal memory (OCMC RAM) during bootup and runs from there.

As part of the low power entry (DeepSleep0 mode in AM33XX TRM), the code running from OCMC RAM does the following
1. Stores the EMIF configuration
2. Puts external memory in self-refresh
3. Disables EMIF clock
4. Executes WFI after writing to MPU_CLKCTRL register.

...snip...
...snip...

arch/arm/mach-omap2/sleep33xx.S line 104

Quoted 8 lines
arch/arm/mach-omap2/sleep33xx.S new file +8 -0
+	ldr	r1, [r0, #EMIF_DDR_PHY_CTRL_1]
+	str	r1, emif_rd_lat_val
+
+	/* Put SDRAM in self-refresh */
+	ldr	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	orr	r1, r1, #0xa0
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
+	str	r1, [r0, #4]

This seems to be a bug which I had pointed out to VB earlier.

r0 ---> base of emif module

r0 + 4 ---> EMIF4_0_SDRAM_STATUS ===> which is read only register

Above 2 lines should be as below

(quoted diff) +2 -0
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CONTROL]
+	str	r1, [r0, #EMIF_POWER_MANAGEMENT_CTRL_SHDW]
Quoted 7 lines

It works even with the bug because the Shadow register is updated and that some how seems to take precedence.

Thanks & regards
Gururaja

Thanks for pointing this out, I have fixed it for next version.

Regards,
Dave

Quoted 5 lines
Quoted 4 lines
arch/arm/mach-omap2/sleep33xx.S new file +3 -0
+
+	ldr	r1, dram_sync_word	@ a dummy access to DDR as per spec
+	ldr	r2, [r1, #0]
#46 lore raw

PATCH v3 6/9 ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state.

commit adc78e6 (timekeeping: Add suspend and resume of clock event devices) introduced .suspend and .resume callbacks for clock event devices. Leverages these callbacks to have AM33XX clockevent timer which is in not in WKUP domain to behave properly across system suspend.

---
 arch/arm/mach-omap2/timer.c |   32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/mach-omap2/timer.c +32 -0
index b37e1fc..cce5d39 100644
@@ -118,11 +118,43 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 	}
 }
 
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);
+	if (!oh)
+		return;
+
+	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
+	omap_hwmod_idle(oh);
+}
+
+static void omap_clkevt_resume(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);
+	if (!oh)
+		return;
+
+	omap_hwmod_enable(oh);
+	__omap_dm_timer_load_start(&clkev,
+			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+}
+
 static struct clock_event_device clockevent_gpt = {
 	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 	.rating		= 300,
 	.set_next_event	= omap2_gp_timer_set_next_event,
 	.set_mode	= omap2_gp_timer_set_mode,
+	.suspend	= omap_clkevt_suspend,
+	.resume		= omap_clkevt_resume,
 };
 
 static struct property device_disabled = {
Signature · 1 line
1.7.9.5
#47 lore raw

PATCH v3 6/9 ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device

Quoted 14 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state.

commit adc78e6 (timekeeping: Add suspend and resume of clock event devices) introduced .suspend and .resume callbacks for clock event devices. Leverages these callbacks to have AM33XX clockevent timer which is in not in WKUP domain to behave properly across system suspend.

Quoted 2 lines
Quoted 59 lines
---
 arch/arm/mach-omap2/timer.c |   32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/mach-omap2/timer.c +32 -1
index b37e1fc..cce5d39 100644
@@ -118,11 +118,43 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
        }
 }
 
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+       char name[10];
+       struct omap_hwmod *oh;
+
+       sprintf(name, "timer%d", clkev.id);
+       oh = omap_hwmod_lookup(name);
+       if (!oh)
+               return;
+
+       __omap_dm_timer_stop(&clkev, 1, clkev.rate);
+       omap_hwmod_idle(oh);
+}
+
+static void omap_clkevt_resume(struct clock_event_device *unused)
+{
+       char name[10];
+       struct omap_hwmod *oh;
+
+       sprintf(name, "timer%d", clkev.id);
+       oh = omap_hwmod_lookup(name);
+       if (!oh)
+               return;
+
+       omap_hwmod_enable(oh);
+       __omap_dm_timer_load_start(&clkev,
+                       OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+       __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+}
+
 static struct clock_event_device clockevent_gpt = {
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
        .rating         = 300,
        .set_next_event = omap2_gp_timer_set_next_event,
        .set_mode       = omap2_gp_timer_set_mode,
+       .suspend        = omap_clkevt_suspend,
+       .resume         = omap_clkevt_resume,
 };
 
 static struct property device_disabled = {
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#48 lore raw

PATCH v3 6/9 ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device

In reply to Dave Gerlach
Quoted 14 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state.

commit adc78e6 (timekeeping: Add suspend and resume of clock event devices) introduced .suspend and .resume callbacks for clock event devices. Leverages these callbacks to have AM33XX clockevent timer which is in not in WKUP domain to behave properly across system suspend.

Quoted 3 lines

---

NAK

This patch doesn't addressed previous comments.
- The issue is specific to AM33XX and hence you need to take care of that. These callbacks will happen on all OMAP machines where the problem doesn't exist.

- Don't use hwmod APIs directly. At least abstract it at omap_device layer and use that one instead.

Quoted 52 lines
 arch/arm/mach-omap2/timer.c |   32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/mach-omap2/timer.c +32 -0
index b37e1fc..cce5d39 100644
@@ -118,11 +118,43 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 	}
 }
 
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);
+	if (!oh)
+		return;
+
+	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
+	omap_hwmod_idle(oh);
+}
+
+static void omap_clkevt_resume(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);
+	if (!oh)
+		return;
+
+	omap_hwmod_enable(oh);
+	__omap_dm_timer_load_start(&clkev,
+			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+}
+
 static struct clock_event_device clockevent_gpt = {
 	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 	.rating		= 300,
 	.set_next_event	= omap2_gp_timer_set_next_event,
 	.set_mode	= omap2_gp_timer_set_mode,
+	.suspend	= omap_clkevt_suspend,
+	.resume		= omap_clkevt_resume,
 };
 
 static struct property device_disabled = {
#49 lore raw

PATCH v3 6/9 ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device

Quoted 20 lines · Santosh Shilimkar
Quoted 14 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state.

commit adc78e6 (timekeeping: Add suspend and resume of clock event devices) introduced .suspend and .resume callbacks for clock event devices. Leverages these callbacks to have AM33XX clockevent timer which is in not in WKUP domain to behave properly across system suspend.

Quoted 3 lines

---

NAK

Quoted 8 lines

This patch doesn't addressed previous comments.
- The issue is specific to AM33XX and hence you need to take care of that. These callbacks will happen on all OMAP machines where the problem doesn't exist.

- Don't use hwmod APIs directly. At least abstract it at omap_device layer and use that one instead.

Ok I will fix this, seems I missed those.

Quoted 53 lines
Quoted 52 lines
  arch/arm/mach-omap2/timer.c |   32 ++++++++++++++++++++++++++++++++
  1 file changed, 32 insertions(+)
arch/arm/mach-omap2/timer.c +32 -0
index b37e1fc..cce5d39 100644
@@ -118,11 +118,43 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
  	}
  }
 
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);
+	if (!oh)
+		return;
+
+	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
+	omap_hwmod_idle(oh);
+}
+
+static void omap_clkevt_resume(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);
+	if (!oh)
+		return;
+
+	omap_hwmod_enable(oh);
+	__omap_dm_timer_load_start(&clkev,
+			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
+	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
+}
+
  static struct clock_event_device clockevent_gpt = {
  	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  	.rating		= 300,
  	.set_next_event	= omap2_gp_timer_set_next_event,
  	.set_mode	= omap2_gp_timer_set_mode,
+	.suspend	= omap_clkevt_suspend,
+	.resume		= omap_clkevt_resume,
  };
 
  static struct property device_disabled = {
#50 lore raw

PATCH v3 6/9 ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device

In reply to Dave Gerlach
Quoted 25 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state.

commit adc78e6 (timekeeping: Add suspend and resume of clock event devices) introduced .suspend and .resume callbacks for clock event devices. Leverages these callbacks to have AM33XX clockevent timer which is in not in WKUP domain to behave properly across system suspend.

---
 arch/arm/mach-omap2/timer.c |   32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
arch/arm/mach-omap2/timer.c +0 -0
index b37e1fc..cce5d39 100644

arch/arm/mach-omap2/timer.c static void omap2_gp_timer_set_mode(enum clock_event_mode mode, · line 127

Quoted 10 lines
arch/arm/mach-omap2/timer.c +7 -0
@@ -118,11 +118,43 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
 	}
 }
 
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);

/me stops reviewing here. This should be a one-time thing.

Seeing things *again* in patches that I've already reviewed (multiple times) is very frustrating. It also increases the likelihood of future patches to be "filtered." (in this case, you get a pass since you seem to have inherited Vaibhav's code, but please take care to address all reviewer comments, or at least explain why you didn'.)

Kevin

#51 lore raw

PATCH v3 6/9 ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device

Quoted 40 lines · Kevin Hilman
Quoted 25 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state.

commit adc78e6 (timekeeping: Add suspend and resume of clock event devices) introduced .suspend and .resume callbacks for clock event devices. Leverages these callbacks to have AM33XX clockevent timer which is in not in WKUP domain to behave properly across system suspend.

---
  arch/arm/mach-omap2/timer.c |   32 ++++++++++++++++++++++++++++++++
  1 file changed, 32 insertions(+)
arch/arm/mach-omap2/timer.c +0 -0
index b37e1fc..cce5d39 100644

arch/arm/mach-omap2/timer.c static void omap2_gp_timer_set_mode(enum clock_event_mode mode, · line 127

Quoted 10 lines
arch/arm/mach-omap2/timer.c +7 -0
@@ -118,11 +118,43 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
  	}
  }
 
+static void omap_clkevt_suspend(struct clock_event_device *unused)
+{
+	char name[10];
+	struct omap_hwmod *oh;
+
+	sprintf(name, "timer%d", clkev.id);
+	oh = omap_hwmod_lookup(name);

/me stops reviewing here. This should be a one-time thing.

Quoted 8 lines

Seeing things *again* in patches that I've already reviewed (multiple times) is very frustrating. It also increases the likelihood of future patches to be "filtered." (in this case, you get a pass since you seem to have inherited Vaibhav's code, but please take care to address all reviewer comments, or at least explain why you didn'.)

Kevin

Sorry for missing this. Seems I missed this patch completely when taking over. I'll make sure it's addressed in the next version.

Regards,
Dave

#52 lore raw

PATCH v3 7/9 ARM: OMAP: omap_device: Add APIs to enable and idle hwmods

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Needed to let the AM335x PM handle the IPs which need forced standby transition during every suspend-resume cycle when the corresponding driver is not compiled into the kernel.

---
 arch/arm/mach-omap2/omap_device.c |    8 ++++++++
 arch/arm/mach-omap2/omap_device.h |    2 ++
 2 files changed, 10 insertions(+)
arch/arm/mach-omap2/omap_device.c +8 -0
index 5cc9287..8cf63f6 100644
@@ -219,6 +219,10 @@ static int _omap_device_enable_hwmods(struct omap_device *od)
 	return 0;
 }
 
+int omap_device_enable_hwmods(struct omap_device *od)
+{
+	return _omap_device_enable_hwmods(od);
+}
 /**
  * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
  * @od: struct omap_device *od
@@ -236,6 +240,10 @@ static int _omap_device_idle_hwmods(struct omap_device *od)
 	return 0;
 }
 
+int omap_device_idle_hwmods(struct omap_device *od)
+{
+	return _omap_device_idle_hwmods(od);
+}
 /* Public functions for use by core code */
 
 /**
arch/arm/mach-omap2/omap_device.h +2 -0
index 17ca1ae..655ec35 100644
@@ -87,6 +87,8 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name);
 
 /* OMAP PM interface */
 int omap_device_get_context_loss_count(struct platform_device *pdev);
+int omap_device_enable_hwmods(struct omap_device *od);
+int omap_device_idle_hwmods(struct omap_device *od);
 
 /* Other */
 
Signature · 1 line
1.7.9.5
#53 lore raw

PATCH v3 7/9 ARM: OMAP: omap_device: Add APIs to enable and idle hwmods

Quoted 8 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Needed to let the AM335x PM handle the IPs which need forced standby transition during every suspend-resume cycle when the corresponding driver is not compiled into the kernel.

Quoted 51 lines
---
 arch/arm/mach-omap2/omap_device.c |    8 ++++++++
 arch/arm/mach-omap2/omap_device.h |    2 ++
 2 files changed, 10 insertions(+)
arch/arm/mach-omap2/omap_device.c +8 -0
index 5cc9287..8cf63f6 100644
@@ -219,6 +219,10 @@ static int _omap_device_enable_hwmods(struct omap_device *od)
        return 0;
 }
 
+int omap_device_enable_hwmods(struct omap_device *od)
+{
+       return _omap_device_enable_hwmods(od);
+}
 /**
  * _omap_device_idle_hwmods - call omap_hwmod_idle() on all hwmods
  * @od: struct omap_device *od
@@ -236,6 +240,10 @@ static int _omap_device_idle_hwmods(struct omap_device *od)
        return 0;
 }
 
+int omap_device_idle_hwmods(struct omap_device *od)
+{
+       return _omap_device_idle_hwmods(od);
+}
 /* Public functions for use by core code */
 
 /**
arch/arm/mach-omap2/omap_device.h +2 -1
index 17ca1ae..655ec35 100644
@@ -87,6 +87,8 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name);
 
 /* OMAP PM interface */
 int omap_device_get_context_loss_count(struct platform_device *pdev);
+int omap_device_enable_hwmods(struct omap_device *od);
+int omap_device_idle_hwmods(struct omap_device *od);
 
 /* Other */
 
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#54 lore raw

PATCH v3 7/9 ARM: OMAP: omap_device: Add APIs to enable and idle hwmods

In reply to Dave Gerlach
Quoted 6 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

Needed to let the AM335x PM handle the IPs which need forced standby transition during every suspend-resume cycle when the corresponding driver is not compiled into the kernel.

Quoted 7 lines
---
 arch/arm/mach-omap2/omap_device.c |    8 ++++++++
 arch/arm/mach-omap2/omap_device.h |    2 ++
 2 files changed, 10 insertions(+)

The interface might be sane but the need of force standby is just non-sense. Why can't we take care of this in firmware itself. Linux doesn't need to know about it. More comments on this in other patch where it is being used.

Regards,
Santosh

#55 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

AM335x supports various low power modes as documented in section 8.1.4.3 of the AM335x TRM which is available @ http://www.ti.com/litv/pdf/spruh73f

DeepSleep0 mode offers the lowest power mode with limited wakeup sources without a system reboot and is mapped as the suspend state in the kernel. In this state, MPU and PER domains are turned off with the internal RAM held in retention to facilitate resume process. As part of the boot process, the assembly code is copied over to OCMCRAM using the OMAP SRAM code.

AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU in DeepSleep0 entry and exit. WKUP_M3 takes care of the clockdomain and powerdomain transitions based on the intended low power state. MPU needs to load the appropriate WKUP_M3 binary onto the WKUP_M3 memory space before it can leverage any of the PM features like DeepSleep.

The IPC mechanism between MPU and WKUP_M3 uses a mailbox sub-module and 8 IPC registers in the Control module. MPU uses the assigned Mailbox for issuing an interrupt to WKUP_M3 which then goes and checks the IPC registers for the payload. WKUP_M3 has the ability to trigger on interrupt to MPU by executing the "sev" instruction.

In the current implementation when the suspend process is initiated MPU interrupts the WKUP_M3 to let it know about the intent of entering DeepSleep0 and waits for an ACK. When the ACK is received MPU continues with its suspend process to suspend all the drivers and then jumps to assembly in OCMC RAM. The assembly code puts the PLLs in bypass, puts the external RAM in self-refresh mode and then finally execute the WFI instruction. Execution of the WFI instruction triggers another interrupt to the WKUP_M3 which then continues wiht the power down sequence wherein the clockdomain and powerdomain transition takes place. As part of the sleep sequence, WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI execution on WKUP_M3 causes the hardware to disable the main oscillator of the SoC.

When a wakeup event occurs, WKUP_M3 starts the power-up sequence by switching on the power domains and finally enabling the clock to MPU. Since the MPU gets powered down as part of the sleep sequence in the resume path ROM code starts executing. The ROM code detects a wakeup from sleep and then jumps to the resume location in OCMC which was populated in one of the IPC registers as part of the suspend sequence.

The low level code in OCMC relocks the PLLs, enables access to external RAM and then jumps to the cpu_resume code of the kernel to finish the resume process.

Cc Tony Lingren <[email protected]>
Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/pm33xx.c  |  474 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h  |   77 +++++++
 arch/arm/mach-omap2/wkup_m3.c |  183 ++++++++++++++++
 3 files changed, 734 insertions(+)
 create mode 100644 arch/arm/mach-omap2/pm33xx.c
 create mode 100644 arch/arm/mach-omap2/pm33xx.h
 create mode 100644 arch/arm/mach-omap2/wkup_m3.c
arch/arm/mach-omap2/pm33xx.c new file +474 -0
new file mode 100644
index 0000000..d291c76
@@ -0,0 +1,474 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ti_emif.h>
+#include <linux/omap-mailbox.h>
+
+#include <asm/suspend.h>
+#include <asm/proc-fns.h>
+#include <asm/sizes.h>
+#include <asm/fncpy.h>
+#include <asm/system_misc.h>
+
+#include "pm.h"
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "control.h"
+#include "common.h"
+#include "clockdomain.h"
+#include "powerdomain.h"
+#include "omap_hwmod.h"
+#include "omap_device.h"
+#include "soc.h"
+#include "sram.h"
+
+static void __iomem *am33xx_emif_base;
+static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
+static struct clockdomain *gfx_l4ls_clkdm;
+
+struct wakeup_src wakeups[] = {
+	{.irq_nr = 35,	.src = "USB0_PHY"},
+	{.irq_nr = 36,	.src = "USB1_PHY"},
+	{.irq_nr = 40,	.src = "I2C0"},
+	{.irq_nr = 41,	.src = "RTC Timer"},
+	{.irq_nr = 42,	.src = "RTC Alarm"},
+	{.irq_nr = 43,	.src = "Timer0"},
+	{.irq_nr = 44,	.src = "Timer1"},
+	{.irq_nr = 45,	.src = "UART"},
+	{.irq_nr = 46,	.src = "GPIO0"},
+	{.irq_nr = 48,	.src = "MPU_WAKE"},
+	{.irq_nr = 49,	.src = "WDT0"},
+	{.irq_nr = 50,	.src = "WDT1"},
+	{.irq_nr = 51,	.src = "ADC_TSC"},
+};
+
+struct forced_standby_module am33xx_mod[] = {
+	{.oh_name = "usb_otg_hs"},
+	{.oh_name = "tptc0"},
+	{.oh_name = "tptc1"},
+	{.oh_name = "tptc2"},
+	{.oh_name = "cpgmac0"},
+};
+
+static struct am33xx_pm_context *am33xx_pm;
+
+static DECLARE_COMPLETION(am33xx_pm_sync);
+
+static void (*am33xx_do_wfi_sram)(struct am33xx_suspend_params *);
+
+static struct am33xx_suspend_params susp_params;
+
+#ifdef CONFIG_SUSPEND
+
+static int am33xx_do_sram_idle(long unsigned int unused)
+{
+	am33xx_do_wfi_sram(&susp_params);
+	return 0;
+}
+
+static int am33xx_pm_suspend(void)
+{
+	int i, j, ret = 0;
+
+	int status = 0;
+	struct platform_device *pdev;
+	struct omap_device *od;
+
+	/*
+	 * By default the following IPs do not have MSTANDBY asserted
+	 * which is necessary for PER domain transition. If the drivers
+	 * are not compiled into the kernel HWMOD code will not change the
+	 * state of the IPs if the IP was not never enabled. To ensure
+	 * that there no issues with or without the drivers being compiled
+	 * in the kernel, we forcefully put these IPs to idle.
+	 */
+	for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+		pdev = to_platform_device(am33xx_mod[i].dev);
+		od = to_omap_device(pdev);
+		if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+			omap_device_enable_hwmods(od);
+			omap_device_idle_hwmods(od);
+		}
+	}
+
+	/* Try to put GFX to sleep */
+	omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
+	ret = cpu_suspend(0, am33xx_do_sram_idle);
+
+	status = pwrdm_read_prev_pwrst(gfx_pwrdm);
+	if (status != PWRDM_POWER_OFF)
+		pr_err("PM: GFX domain did not transition\n");
+	else
+		pr_info("PM: GFX domain entered low power state\n");
+
+	/*
+	 * BUG: GFX_L4LS clock domain needs to be woken up to
+	 * ensure thet L4LS clock domain does not get stuck in transition
+	 * If that happens L3 module does not get disabled, thereby leading
+	 * to PER power domain transition failing
+	 */
+	clkdm_wakeup(gfx_l4ls_clkdm);
+	clkdm_sleep(gfx_l4ls_clkdm);
+
+	if (ret) {
+		pr_err("PM: Kernel suspend failure\n");
+	} else {
+		i = am33xx_pm_status();
+		switch (i) {
+		case 0:
+			pr_info("PM: Successfully put all powerdomains to target state\n");
+
+			/*
+			 * The PRCM registers on AM335x do not contain previous state
+			 * information like those present on OMAP4 so we must manually
+			 * indicate transition so state counters are properly incremented
+			 */
+			pwrdm_post_transition(mpu_pwrdm);
+			pwrdm_post_transition(per_pwrdm);
+			break;
+		case 1:
+			pr_err("PM: Could not transition all powerdomains to target state\n");
+			ret = -1;
+			break;
+		default:
+			pr_err("PM: CM3 returned unknown result :(\nStatus = %d\n", i);
+			ret = -1;
+		}
+
+		/* print the wakeup reason */
+		i = am33xx_pm_wake_src();
+		for (j = 0; j < ARRAY_SIZE(wakeups); j++) {
+			if (wakeups[j].irq_nr == i) {
+				pr_info("PM: Wakeup source %s\n", wakeups[j].src);
+				break;
+			}
+		}
+
+		if (j == ARRAY_SIZE(wakeups))
+			pr_info("PM: Unknown wakeup source %d!\n", i);
+	}
+
+	return ret;
+}
+
+static int am33xx_pm_enter(suspend_state_t suspend_state)
+{
+	int ret = 0;
+
+	switch (suspend_state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		ret = am33xx_pm_suspend();
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/* returns the error code from msg_send - 0 for success, failure otherwise */
+static int am33xx_ping_wkup_m3(void)
+{
+	int ret = 0;
+
+	/*
+	 * Write a dummy message to the mailbox in order to trigger the RX
+	 * interrupt to alert the M3 that data is available in the IPC
+	 * registers.
+	 */
+	ret = omap_mbox_msg_send(am33xx_pm->mbox, 0xABCDABCD);
+
+	return ret;
+}
+
+static void am33xx_m3_state_machine_reset(void)
+{
+	int i;
+
+	am33xx_pm->ipc.sleep_mode = IPC_CMD_RESET;
+
+	am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
+
+	am33xx_pm->state = M3_STATE_MSG_FOR_RESET;
+
+	pr_info("PM: Sending message for resetting M3 state machine\n");
+
+	if (!am33xx_ping_wkup_m3()) {
+		i = wait_for_completion_timeout(&am33xx_pm_sync,
+					msecs_to_jiffies(500));
+		if (WARN(i == 0, "PM: MPU<->CM3 sync failure\n"))
+			am33xx_pm->state = M3_STATE_UNKNOWN;
+	} else {
+		pr_warn("PM: Unable to ping CM3\n");
+	}
+}
+
+static int am33xx_pm_begin(suspend_state_t state)
+{
+	int i;
+
+	cpu_idle_poll_ctrl(true);
+
+	am33xx_pm->ipc.sleep_mode	= IPC_CMD_DS0;
+	am33xx_pm->ipc.param1		= DS_IPC_DEFAULT;
+	am33xx_pm->ipc.param2		= DS_IPC_DEFAULT;
+
+	am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
+
+	am33xx_pm->state = M3_STATE_MSG_FOR_LP;
+
+	pr_info("PM: Sending message for entering DeepSleep mode\n");
+
+	if (!am33xx_ping_wkup_m3()) {
+		i = wait_for_completion_timeout(&am33xx_pm_sync,
+					msecs_to_jiffies(500));
+		if (WARN(i == 0, "PM: MPU<->CM3 sync failure\n"))
+			return -1;
+	} else {
+		pr_warn("PM: Unable to ping CM3\n");
+	}
+
+	return 0;
+}
+
+static void am33xx_pm_end(void)
+{
+	am33xx_m3_state_machine_reset();
+
+	cpu_idle_poll_ctrl(false);
+
+	return;
+}
+
+static struct platform_suspend_ops am33xx_pm_ops = {
+	.begin		= am33xx_pm_begin,
+	.end		= am33xx_pm_end,
+	.enter		= am33xx_pm_enter,
+};
+
+/*
+ * Dummy notifier for the mailbox
+ */
+
+static int wkup_mbox_msg(struct notifier_block *self, unsigned long len,
+		void *msg)
+{
+	return 0;
+}
+
+static struct notifier_block wkup_mbox_notifier = {
+	.notifier_call = wkup_mbox_msg,
+};
+
+void am33xx_txev_handler(void)
+{
+	switch (am33xx_pm->state) {
+	case M3_STATE_RESET:
+		am33xx_pm->state = M3_STATE_INITED;
+		am33xx_pm->ver = am33xx_pm_version_get();
+		if (am33xx_pm->ver == M3_VERSION_UNKNOWN ||
+			am33xx_pm->ver < M3_BASELINE_VERSION) {
+			pr_warn("PM: CM3 Firmware Version %x not supported\n",
+						am33xx_pm->ver);
+		} else {
+			pr_info("PM: CM3 Firmware Version = 0x%x\n",
+						am33xx_pm->ver);
+			am33xx_pm_ops.valid = suspend_valid_only_mem;
+		}
+		break;
+	case M3_STATE_MSG_FOR_RESET:
+		am33xx_pm->state = M3_STATE_INITED;
+		complete(&am33xx_pm_sync);
+		break;
+	case M3_STATE_MSG_FOR_LP:
+		complete(&am33xx_pm_sync);
+		break;
+	case M3_STATE_UNKNOWN:
+		pr_warn("PM: Unknown CM3 State\n");
+	}
+
+	return;
+}
+
+static void am33xx_pm_firmware_cb(const struct firmware *fw, void *context)
+{
+	struct am33xx_pm_context *am33xx_pm = context;
+	int ret = 0;
+
+	/* no firmware found */
+	if (!fw) {
+		pr_err("PM: request_firmware failed\n");
+		return;
+	}
+
+	wkup_m3_copy_code(fw->data, fw->size);
+
+	wkup_m3_register_txev_handler(am33xx_txev_handler);
+
+	pr_info("PM: Copied the M3 firmware to UMEM\n");
+
+	/*
+	 * Invalidate M3 firmware version before hardreset.
+	 * Write invalid version in lower 4 nibbles of parameter
+	 * register (ipc_regs + 0x8).
+	 */
+	am33xx_pm_version_clear();
+
+	am33xx_pm->state = M3_STATE_RESET;
+
+	ret = wkup_m3_prepare();
+	if (ret) {
+		pr_err("PM: Could not prepare WKUP_M3\n");
+		return;
+	}
+
+	/* Physical resume address to be used by ROM code */
+	am33xx_pm->ipc.resume_addr = (AM33XX_OCMC_END -
+		am33xx_do_wfi_sz + am33xx_resume_offset + 0x4);
+
+	am33xx_pm->mbox = omap_mbox_get("wkup_m3", &wkup_mbox_notifier);
+
+	if (IS_ERR(am33xx_pm->mbox)) {
+		ret = -EBUSY;
+		pr_err("PM: IPC Request for A8->M3 Channel failed!\n");
+		return;
+	} else {
+		suspend_set_ops(&am33xx_pm_ops);
+	}
+
+	return;
+}
+
+#endif /* CONFIG_SUSPEND */
+
+/*
+ * Push the minimal suspend-resume code to SRAM
+ */
+void am33xx_push_sram_idle(void)
+{
+	am33xx_do_wfi_sram = (void *)omap_sram_push
+					(am33xx_do_wfi, am33xx_do_wfi_sz);
+}
+
+static int __init am33xx_map_emif(void)
+{
+	am33xx_emif_base = ioremap(AM33XX_EMIF_BASE, SZ_32K);
+
+	if (!am33xx_emif_base)
+		return -ENOMEM;
+
+	return 0;
+}
+
+int __init am33xx_pm_init(void)
+{
+	int ret;
+	u32 temp;
+	struct device_node *np;
+	int i;
+
+	if (!soc_is_am33xx())
+		return -ENODEV;
+
+	pr_info("Power Management for AM33XX family\n");
+
+	/*
+	 * By default the following IPs do not have MSTANDBY asserted
+	 * which is necessary for PER domain transition. If the drivers
+	 * are not compiled into the kernel HWMOD code will not change the
+	 * state of the IPs if the IP was not never enabled
+	 */
+	for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++)
+		am33xx_mod[i].dev = omap_device_get_by_hwmod_name(am33xx_mod[i].oh_name);
+
+	gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
+	per_pwrdm = pwrdm_lookup("per_pwrdm");
+	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+
+	gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
+
+	if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm) || (!gfx_l4ls_clkdm)) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	am33xx_pm = kzalloc(sizeof(*am33xx_pm), GFP_KERNEL);
+	if (!am33xx_pm) {
+		pr_err("Memory allocation failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = am33xx_map_emif();
+	if (ret) {
+		pr_err("PM: Could not ioremap EMIF\n");
+		goto err;
+	}
+	/* Determine Memory Type */
+	temp = readl(am33xx_emif_base + EMIF_SDRAM_CONFIG);
+	temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
+	/* Parameters to pass to aseembly code */
+	susp_params.emif_addr_virt = am33xx_emif_base;
+	susp_params.dram_sync = am33xx_dram_sync;
+	susp_params.mem_type = temp;
+	am33xx_pm->ipc.param3 = temp;
+
+	np = of_find_compatible_node(NULL, NULL, "ti,am3353-wkup-m3");
+	if (np) {
+		if (of_find_property(np, "ti,needs_vtt_toggle", NULL) &&
+		    (!(of_property_read_u32(np, "vtt-gpio-pin",
+							&temp)))) {
+			if (temp >= 0 && temp <= 31)
+				am33xx_pm->ipc.param3 |=
+					((1 << VTT_STAT_SHIFT) |
+					(temp << VTT_GPIO_PIN_SHIFT));
+		}
+	}
+
+	(void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
+
+	/* CEFUSE domain can be turned off post bootup */
+	cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
+	if (cefuse_pwrdm)
+		omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
+	else
+		pr_err("PM: Failed to get cefuse_pwrdm\n");
+
+#ifdef CONFIG_SUSPEND
+	pr_info("PM: Trying to load am335x-pm-firmware.bin");
+
+	/* We don't want to delay boot */
+	request_firmware_nowait(THIS_MODULE, 0, "am335x-pm-firmware.bin",
+				NULL, GFP_KERNEL, am33xx_pm,
+				am33xx_pm_firmware_cb);
+#endif /* CONFIG_SUSPEND */
+
+err:
+	return ret;
+}
arch/arm/mach-omap2/pm33xx.h new file +77 -0

77 lines not on this page · raw message

arch/arm/mach-omap2/wkup_m3.c new file +183 -0

183 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#56 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

On 08/06/2013 12:49 PM, Dave Gerlach wrote:
[...]

Quoted 9 lines
arch/arm/mach-omap2/pm33xx.c new file +9 -0
+
+struct forced_standby_module am33xx_mod[] = {
+	{.oh_name = "usb_otg_hs"},
+	{.oh_name = "tptc0"},
+	{.oh_name = "tptc1"},
+	{.oh_name = "tptc2"},
+	{.oh_name = "cpgmac0"},
+};
+

[...]

Quoted 15 lines
arch/arm/mach-omap2/pm33xx.c new file +15 -0
+
+static int am33xx_pm_suspend(void)
+{
+	int i, j, ret = 0;
+
+	int status = 0;
+	struct platform_device *pdev;
+	struct omap_device *od;
+
+	/*
+	 * By default the following IPs do not have MSTANDBY asserted
+	 * which is necessary for PER domain transition. If the drivers
+	 * are not compiled into the kernel HWMOD code will not change the
+	 * state of the IPs if the IP was not never enabled. To ensure
+	 * that there no issues with or without the drivers being compiled

arch/arm/mach-omap2/pm33xx.c line 117

Quoted 10 lines
arch/arm/mach-omap2/pm33xx.c new file +10 -0
+	 * in the kernel, we forcefully put these IPs to idle.
+	 */
+	for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+		pdev = to_platform_device(am33xx_mod[i].dev);
+		od = to_omap_device(pdev);
+		if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+			omap_device_enable_hwmods(od);
+			omap_device_idle_hwmods(od);
+		}
+	}

Sorry, I dont like this one bit. this is the job of the suspend / resume handler dealing with the specific device. I recollect having a similar issue on OMAP5 where without USB driver, USB wont idle, hence we cant suspend either. is the solution to do a custom handling for specific nodes as above? is it even necessary - considering that in multiple suspend-resume iterations, do we need to "enable and idle" multiple times? Cant we do it just in hwmod/omap_device level where unbound devices are disabled? Is there absolutely no possible way to do this in a generic manner?

Signature · 2 lines
Regards,
Nishanth Menon
#57 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Nishanth,
The issue here is that during a low-power transition the peripheral power domain loses context so the MSTANDBY config gets lost which is why the custom handling is needed on every cycle if there is no driver to handle it. I was unable to come up with a more generic way to handle this but I am certainly open for suggestions.

Regards,
Dave

Quoted 49 lines · Nishanth Menon

On 08/06/2013 12:49 PM, Dave Gerlach wrote:
[...]

Quoted 9 lines
arch/arm/mach-omap2/pm33xx.c new file +9 -0
+
+struct forced_standby_module am33xx_mod[] = {
+    {.oh_name = "usb_otg_hs"},
+    {.oh_name = "tptc0"},
+    {.oh_name = "tptc1"},
+    {.oh_name = "tptc2"},
+    {.oh_name = "cpgmac0"},
+};
+

[...]

Quoted 15 lines
arch/arm/mach-omap2/pm33xx.c new file +15 -0
+
+static int am33xx_pm_suspend(void)
+{
+    int i, j, ret = 0;
+
+    int status = 0;
+    struct platform_device *pdev;
+    struct omap_device *od;
+
+    /*
+     * By default the following IPs do not have MSTANDBY asserted
+     * which is necessary for PER domain transition. If the drivers
+     * are not compiled into the kernel HWMOD code will not change the
+     * state of the IPs if the IP was not never enabled. To ensure
+     * that there no issues with or without the drivers being compiled

arch/arm/mach-omap2/pm33xx.c line 117

Quoted 10 lines
arch/arm/mach-omap2/pm33xx.c new file +10 -0
+     * in the kernel, we forcefully put these IPs to idle.
+     */
+    for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+        pdev = to_platform_device(am33xx_mod[i].dev);
+        od = to_omap_device(pdev);
+        if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+            omap_device_enable_hwmods(od);
+            omap_device_idle_hwmods(od);
+        }
+    }

Sorry, I dont like this one bit. this is the job of the suspend / resume handler dealing with the specific device. I recollect having a similar issue on OMAP5 where without USB driver, USB wont idle, hence we cant suspend either. is the solution to do a custom handling for specific nodes as above? is it even necessary - considering that in multiple suspend-resume iterations, do we need to "enable and idle" multiple times? Cant we do it just in hwmod/omap_device level where unbound devices are disabled? Is there absolutely no possible way to do this in a generic manner?

#58 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 51 lines · Dave Gerlach
Quoted 40 lines · Nishanth Menon

On 08/06/2013 12:49 PM, Dave Gerlach wrote:
[...]

Quoted 9 lines
arch/arm/mach-omap2/pm33xx.c new file +9 -0
+
+struct forced_standby_module am33xx_mod[] = {
+    {.oh_name = "usb_otg_hs"},
+    {.oh_name = "tptc0"},
+    {.oh_name = "tptc1"},
+    {.oh_name = "tptc2"},
+    {.oh_name = "cpgmac0"},
+};
+

[...]

Quoted 15 lines
arch/arm/mach-omap2/pm33xx.c new file +15 -0
+
+static int am33xx_pm_suspend(void)
+{
+    int i, j, ret = 0;
+
+    int status = 0;
+    struct platform_device *pdev;
+    struct omap_device *od;
+
+    /*
+     * By default the following IPs do not have MSTANDBY asserted
+     * which is necessary for PER domain transition. If the drivers
+     * are not compiled into the kernel HWMOD code will not change the
+     * state of the IPs if the IP was not never enabled. To ensure
+     * that there no issues with or without the drivers being compiled

arch/arm/mach-omap2/pm33xx.c line 117

Quoted 10 lines
arch/arm/mach-omap2/pm33xx.c new file +10 -0
+     * in the kernel, we forcefully put these IPs to idle.
+     */
+    for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+        pdev = to_platform_device(am33xx_mod[i].dev);
+        od = to_omap_device(pdev);
+        if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+            omap_device_enable_hwmods(od);
+            omap_device_idle_hwmods(od);
+        }
+    }

Sorry, I dont like this one bit. this is the job of the suspend / resume

Quoted 9 lines

handler dealing with the specific device. I recollect having a similar issue on OMAP5 where without USB driver, USB wont idle, hence we cant suspend either. is the solution to do a custom handling for specific nodes as above? is it even necessary - considering that in multiple suspend-resume iterations, do we need to "enable and idle" multiple times? Cant we do it just in hwmod/omap_device level where unbound devices are disabled? Is there absolutely no possible way to do this in a generic manner?

Quoted 6 lines

The issue here is that during a low-power transition the peripheral power domain loses context so the MSTANDBY config gets lost which is why the custom handling is needed on every cycle if there is no driver to handle it. I was unable to come up with a more generic way to handle this but I am certainly open for suggestions.

If the dts entry for device status = "disabled" you should not have these even registered right? kinda makes me wonder if M3 could do something about it -> since they are minimal?

When they are not,

I think the generic omap_device_pm_domain ops does not apply for these devices due to the quirks?

Making a flag for these improper devices should let omap_device abstraction setup different pm_domain configuration also shut them up at boot as well (if un-bound). that will let a generic device solution scale out to more SoCs without custom handling, perhaps?

just an quick idea - not sure about validity about the approach without digging in more.

usually, we try to ensure system is exactly the same state as it entered -> so at boot, we shut down everything, on wakeup, if unexpected things like these are present, we shut them down again (in .finish handler).

Signature · 2 lines
Regards,
Nishanth Menon
#59 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Dave Gerlach
Quoted 55 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

AM335x supports various low power modes as documented in section 8.1.4.3 of the AM335x TRM which is available @ http://www.ti.com/litv/pdf/spruh73f

DeepSleep0 mode offers the lowest power mode with limited wakeup sources without a system reboot and is mapped as the suspend state in the kernel. In this state, MPU and PER domains are turned off with the internal RAM held in retention to facilitate resume process. As part of the boot process, the assembly code is copied over to OCMCRAM using the OMAP SRAM code.

AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU in DeepSleep0 entry and exit. WKUP_M3 takes care of the clockdomain and powerdomain transitions based on the intended low power state. MPU needs to load the appropriate WKUP_M3 binary onto the WKUP_M3 memory space before it can leverage any of the PM features like DeepSleep.

The IPC mechanism between MPU and WKUP_M3 uses a mailbox sub-module and 8 IPC registers in the Control module. MPU uses the assigned Mailbox for issuing an interrupt to WKUP_M3 which then goes and checks the IPC registers for the payload. WKUP_M3 has the ability to trigger on interrupt to MPU by executing the "sev" instruction.

In the current implementation when the suspend process is initiated MPU interrupts the WKUP_M3 to let it know about the intent of entering DeepSleep0 and waits for an ACK. When the ACK is received MPU continues with its suspend process to suspend all the drivers and then jumps to assembly in OCMC RAM. The assembly code puts the PLLs in bypass, puts the external RAM in self-refresh mode and then finally execute the WFI instruction. Execution of the WFI instruction triggers another interrupt to the WKUP_M3 which then continues wiht the power down sequence wherein the clockdomain and powerdomain transition takes place. As part of the sleep sequence, WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI execution on WKUP_M3 causes the hardware to disable the main oscillator of the SoC.

When a wakeup event occurs, WKUP_M3 starts the power-up sequence by switching on the power domains and finally enabling the clock to MPU. Since the MPU gets powered down as part of the sleep sequence in the resume path ROM code starts executing. The ROM code detects a wakeup from sleep and then jumps to the resume location in OCMC which was populated in one of the IPC registers as part of the suspend sequence.

The low level code in OCMC relocks the PLLs, enables access to external RAM and then jumps to the cpu_resume code of the kernel to finish the resume process.

Quoted 7 lines
Cc Tony Lingren <[email protected]>
Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>

In response to Nishanth's comments about the list of omap modules to idle, I saw that, but it looks like its only for devices that no device driver ever binds do, eg, the support is not built into the kernel or the module is currently not loaded. Hence I don't think there is any suspend/resume function that gets called. In reference to the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 768 lines
---
 arch/arm/mach-omap2/pm33xx.c  |  474 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h  |   77 +++++++
 arch/arm/mach-omap2/wkup_m3.c |  183 ++++++++++++++++
 3 files changed, 734 insertions(+)
 create mode 100644 arch/arm/mach-omap2/pm33xx.c
 create mode 100644 arch/arm/mach-omap2/pm33xx.h
 create mode 100644 arch/arm/mach-omap2/wkup_m3.c
arch/arm/mach-omap2/pm33xx.c new file +474 -0
new file mode 100644
index 0000000..d291c76
@@ -0,0 +1,474 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ti_emif.h>
+#include <linux/omap-mailbox.h>
+
+#include <asm/suspend.h>
+#include <asm/proc-fns.h>
+#include <asm/sizes.h>
+#include <asm/fncpy.h>
+#include <asm/system_misc.h>
+
+#include "pm.h"
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "control.h"
+#include "common.h"
+#include "clockdomain.h"
+#include "powerdomain.h"
+#include "omap_hwmod.h"
+#include "omap_device.h"
+#include "soc.h"
+#include "sram.h"
+
+static void __iomem *am33xx_emif_base;
+static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
+static struct clockdomain *gfx_l4ls_clkdm;
+
+struct wakeup_src wakeups[] = {
+       {.irq_nr = 35,  .src = "USB0_PHY"},
+       {.irq_nr = 36,  .src = "USB1_PHY"},
+       {.irq_nr = 40,  .src = "I2C0"},
+       {.irq_nr = 41,  .src = "RTC Timer"},
+       {.irq_nr = 42,  .src = "RTC Alarm"},
+       {.irq_nr = 43,  .src = "Timer0"},
+       {.irq_nr = 44,  .src = "Timer1"},
+       {.irq_nr = 45,  .src = "UART"},
+       {.irq_nr = 46,  .src = "GPIO0"},
+       {.irq_nr = 48,  .src = "MPU_WAKE"},
+       {.irq_nr = 49,  .src = "WDT0"},
+       {.irq_nr = 50,  .src = "WDT1"},
+       {.irq_nr = 51,  .src = "ADC_TSC"},
+};
+
+struct forced_standby_module am33xx_mod[] = {
+       {.oh_name = "usb_otg_hs"},
+       {.oh_name = "tptc0"},
+       {.oh_name = "tptc1"},
+       {.oh_name = "tptc2"},
+       {.oh_name = "cpgmac0"},
+};
+
+static struct am33xx_pm_context *am33xx_pm;
+
+static DECLARE_COMPLETION(am33xx_pm_sync);
+
+static void (*am33xx_do_wfi_sram)(struct am33xx_suspend_params *);
+
+static struct am33xx_suspend_params susp_params;
+
+#ifdef CONFIG_SUSPEND
+
+static int am33xx_do_sram_idle(long unsigned int unused)
+{
+       am33xx_do_wfi_sram(&susp_params);
+       return 0;
+}
+
+static int am33xx_pm_suspend(void)
+{
+       int i, j, ret = 0;
+
+       int status = 0;
+       struct platform_device *pdev;
+       struct omap_device *od;
+
+       /*
+        * By default the following IPs do not have MSTANDBY asserted
+        * which is necessary for PER domain transition. If the drivers
+        * are not compiled into the kernel HWMOD code will not change the
+        * state of the IPs if the IP was not never enabled. To ensure
+        * that there no issues with or without the drivers being compiled
+        * in the kernel, we forcefully put these IPs to idle.
+        */
+       for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+               pdev = to_platform_device(am33xx_mod[i].dev);
+               od = to_omap_device(pdev);
+               if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+                       omap_device_enable_hwmods(od);
+                       omap_device_idle_hwmods(od);
+               }
+       }
+
+       /* Try to put GFX to sleep */
+       omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
+       ret = cpu_suspend(0, am33xx_do_sram_idle);
+
+       status = pwrdm_read_prev_pwrst(gfx_pwrdm);
+       if (status != PWRDM_POWER_OFF)
+               pr_err("PM: GFX domain did not transition\n");
+       else
+               pr_info("PM: GFX domain entered low power state\n");
+
+       /*
+        * BUG: GFX_L4LS clock domain needs to be woken up to
+        * ensure thet L4LS clock domain does not get stuck in transition
+        * If that happens L3 module does not get disabled, thereby leading
+        * to PER power domain transition failing
+        */
+       clkdm_wakeup(gfx_l4ls_clkdm);
+       clkdm_sleep(gfx_l4ls_clkdm);
+
+       if (ret) {
+               pr_err("PM: Kernel suspend failure\n");
+       } else {
+               i = am33xx_pm_status();
+               switch (i) {
+               case 0:
+                       pr_info("PM: Successfully put all powerdomains to target state\n");
+
+                       /*
+                        * The PRCM registers on AM335x do not contain previous state
+                        * information like those present on OMAP4 so we must manually
+                        * indicate transition so state counters are properly incremented
+                        */
+                       pwrdm_post_transition(mpu_pwrdm);
+                       pwrdm_post_transition(per_pwrdm);
+                       break;
+               case 1:
+                       pr_err("PM: Could not transition all powerdomains to target state\n");
+                       ret = -1;
+                       break;
+               default:
+                       pr_err("PM: CM3 returned unknown result :(\nStatus = %d\n", i);
+                       ret = -1;
+               }
+
+               /* print the wakeup reason */
+               i = am33xx_pm_wake_src();
+               for (j = 0; j < ARRAY_SIZE(wakeups); j++) {
+                       if (wakeups[j].irq_nr == i) {
+                               pr_info("PM: Wakeup source %s\n", wakeups[j].src);
+                               break;
+                       }
+               }
+
+               if (j == ARRAY_SIZE(wakeups))
+                       pr_info("PM: Unknown wakeup source %d!\n", i);
+       }
+
+       return ret;
+}
+
+static int am33xx_pm_enter(suspend_state_t suspend_state)
+{
+       int ret = 0;
+
+       switch (suspend_state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = am33xx_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/* returns the error code from msg_send - 0 for success, failure otherwise */
+static int am33xx_ping_wkup_m3(void)
+{
+       int ret = 0;
+
+       /*
+        * Write a dummy message to the mailbox in order to trigger the RX
+        * interrupt to alert the M3 that data is available in the IPC
+        * registers.
+        */
+       ret = omap_mbox_msg_send(am33xx_pm->mbox, 0xABCDABCD);
+
+       return ret;
+}
+
+static void am33xx_m3_state_machine_reset(void)
+{
+       int i;
+
+       am33xx_pm->ipc.sleep_mode = IPC_CMD_RESET;
+
+       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
+
+       am33xx_pm->state = M3_STATE_MSG_FOR_RESET;
+
+       pr_info("PM: Sending message for resetting M3 state machine\n");
+
+       if (!am33xx_ping_wkup_m3()) {
+               i = wait_for_completion_timeout(&am33xx_pm_sync,
+                                       msecs_to_jiffies(500));
+               if (WARN(i == 0, "PM: MPU<->CM3 sync failure\n"))
+                       am33xx_pm->state = M3_STATE_UNKNOWN;
+       } else {
+               pr_warn("PM: Unable to ping CM3\n");
+       }
+}
+
+static int am33xx_pm_begin(suspend_state_t state)
+{
+       int i;
+
+       cpu_idle_poll_ctrl(true);
+
+       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
+       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
+       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
+
+       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
+
+       am33xx_pm->state = M3_STATE_MSG_FOR_LP;
+
+       pr_info("PM: Sending message for entering DeepSleep mode\n");
+
+       if (!am33xx_ping_wkup_m3()) {
+               i = wait_for_completion_timeout(&am33xx_pm_sync,
+                                       msecs_to_jiffies(500));
+               if (WARN(i == 0, "PM: MPU<->CM3 sync failure\n"))
+                       return -1;
+       } else {
+               pr_warn("PM: Unable to ping CM3\n");
+       }
+
+       return 0;
+}
+
+static void am33xx_pm_end(void)
+{
+       am33xx_m3_state_machine_reset();
+
+       cpu_idle_poll_ctrl(false);
+
+       return;
+}
+
+static struct platform_suspend_ops am33xx_pm_ops = {
+       .begin          = am33xx_pm_begin,
+       .end            = am33xx_pm_end,
+       .enter          = am33xx_pm_enter,
+};
+
+/*
+ * Dummy notifier for the mailbox
+ */
+
+static int wkup_mbox_msg(struct notifier_block *self, unsigned long len,
+               void *msg)
+{
+       return 0;
+}
+
+static struct notifier_block wkup_mbox_notifier = {
+       .notifier_call = wkup_mbox_msg,
+};
+
+void am33xx_txev_handler(void)
+{
+       switch (am33xx_pm->state) {
+       case M3_STATE_RESET:
+               am33xx_pm->state = M3_STATE_INITED;
+               am33xx_pm->ver = am33xx_pm_version_get();
+               if (am33xx_pm->ver == M3_VERSION_UNKNOWN ||
+                       am33xx_pm->ver < M3_BASELINE_VERSION) {
+                       pr_warn("PM: CM3 Firmware Version %x not supported\n",
+                                               am33xx_pm->ver);
+               } else {
+                       pr_info("PM: CM3 Firmware Version = 0x%x\n",
+                                               am33xx_pm->ver);
+                       am33xx_pm_ops.valid = suspend_valid_only_mem;
+               }
+               break;
+       case M3_STATE_MSG_FOR_RESET:
+               am33xx_pm->state = M3_STATE_INITED;
+               complete(&am33xx_pm_sync);
+               break;
+       case M3_STATE_MSG_FOR_LP:
+               complete(&am33xx_pm_sync);
+               break;
+       case M3_STATE_UNKNOWN:
+               pr_warn("PM: Unknown CM3 State\n");
+       }
+
+       return;
+}
+
+static void am33xx_pm_firmware_cb(const struct firmware *fw, void *context)
+{
+       struct am33xx_pm_context *am33xx_pm = context;
+       int ret = 0;
+
+       /* no firmware found */
+       if (!fw) {
+               pr_err("PM: request_firmware failed\n");
+               return;
+       }
+
+       wkup_m3_copy_code(fw->data, fw->size);
+
+       wkup_m3_register_txev_handler(am33xx_txev_handler);
+
+       pr_info("PM: Copied the M3 firmware to UMEM\n");
+
+       /*
+        * Invalidate M3 firmware version before hardreset.
+        * Write invalid version in lower 4 nibbles of parameter
+        * register (ipc_regs + 0x8).
+        */
+       am33xx_pm_version_clear();
+
+       am33xx_pm->state = M3_STATE_RESET;
+
+       ret = wkup_m3_prepare();
+       if (ret) {
+               pr_err("PM: Could not prepare WKUP_M3\n");
+               return;
+       }
+
+       /* Physical resume address to be used by ROM code */
+       am33xx_pm->ipc.resume_addr = (AM33XX_OCMC_END -
+               am33xx_do_wfi_sz + am33xx_resume_offset + 0x4);
+
+       am33xx_pm->mbox = omap_mbox_get("wkup_m3", &wkup_mbox_notifier);
+
+       if (IS_ERR(am33xx_pm->mbox)) {
+               ret = -EBUSY;
+               pr_err("PM: IPC Request for A8->M3 Channel failed!\n");
+               return;
+       } else {
+               suspend_set_ops(&am33xx_pm_ops);
+       }
+
+       return;
+}
+
+#endif /* CONFIG_SUSPEND */
+
+/*
+ * Push the minimal suspend-resume code to SRAM
+ */
+void am33xx_push_sram_idle(void)
+{
+       am33xx_do_wfi_sram = (void *)omap_sram_push
+                                       (am33xx_do_wfi, am33xx_do_wfi_sz);
+}
+
+static int __init am33xx_map_emif(void)
+{
+       am33xx_emif_base = ioremap(AM33XX_EMIF_BASE, SZ_32K);
+
+       if (!am33xx_emif_base)
+               return -ENOMEM;
+
+       return 0;
+}
+
+int __init am33xx_pm_init(void)
+{
+       int ret;
+       u32 temp;
+       struct device_node *np;
+       int i;
+
+       if (!soc_is_am33xx())
+               return -ENODEV;
+
+       pr_info("Power Management for AM33XX family\n");
+
+       /*
+        * By default the following IPs do not have MSTANDBY asserted
+        * which is necessary for PER domain transition. If the drivers
+        * are not compiled into the kernel HWMOD code will not change the
+        * state of the IPs if the IP was not never enabled
+        */
+       for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++)
+               am33xx_mod[i].dev = omap_device_get_by_hwmod_name(am33xx_mod[i].oh_name);
+
+       gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
+       per_pwrdm = pwrdm_lookup("per_pwrdm");
+       mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+
+       gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
+
+       if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm) || (!gfx_l4ls_clkdm)) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       am33xx_pm = kzalloc(sizeof(*am33xx_pm), GFP_KERNEL);
+       if (!am33xx_pm) {
+               pr_err("Memory allocation failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = am33xx_map_emif();
+       if (ret) {
+               pr_err("PM: Could not ioremap EMIF\n");
+               goto err;
+       }
+       /* Determine Memory Type */
+       temp = readl(am33xx_emif_base + EMIF_SDRAM_CONFIG);
+       temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
+       /* Parameters to pass to aseembly code */
+       susp_params.emif_addr_virt = am33xx_emif_base;
+       susp_params.dram_sync = am33xx_dram_sync;
+       susp_params.mem_type = temp;
+       am33xx_pm->ipc.param3 = temp;
+
+       np = of_find_compatible_node(NULL, NULL, "ti,am3353-wkup-m3");
+       if (np) {
+               if (of_find_property(np, "ti,needs_vtt_toggle", NULL) &&
+                   (!(of_property_read_u32(np, "vtt-gpio-pin",
+                                                       &temp)))) {
+                       if (temp >= 0 && temp <= 31)
+                               am33xx_pm->ipc.param3 |=
+                                       ((1 << VTT_STAT_SHIFT) |
+                                       (temp << VTT_GPIO_PIN_SHIFT));
+               }
+       }
+
+       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
+
+       /* CEFUSE domain can be turned off post bootup */
+       cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
+       if (cefuse_pwrdm)
+               omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
+       else
+               pr_err("PM: Failed to get cefuse_pwrdm\n");
+
+#ifdef CONFIG_SUSPEND
+       pr_info("PM: Trying to load am335x-pm-firmware.bin");
+
+       /* We don't want to delay boot */
+       request_firmware_nowait(THIS_MODULE, 0, "am335x-pm-firmware.bin",
+                               NULL, GFP_KERNEL, am33xx_pm,
+                               am33xx_pm_firmware_cb);
+#endif /* CONFIG_SUSPEND */
+
+err:
+       return ret;
+}
arch/arm/mach-omap2/pm33xx.h new file +77 -0
new file mode 100644
index 0000000..befdd11
@@ -0,0 +1,77 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_PM33XX_H
+#define __ARCH_ARM_MACH_OMAP2_PM33XX_H
+
+#include "control.h"
+
+#ifndef __ASSEMBLER__
+
+struct am33xx_pm_context {
+       struct am33xx_ipc_data  ipc;
+       struct firmware         *firmware;
+       struct omap_mbox        *mbox;
+       u8                      state;
+       u32                     ver;
+};
+
+/*
+ * Params passed to suspend routine
+ *
+ * Since these are used to load into registers by suspend code,
+ * entries here must always be in sync with the suspend code
+ * in arm/mach-omap2/sleep33xx.S
+ */
+struct am33xx_suspend_params {
+       void __iomem *emif_addr_virt;
+       u32 mem_type;
+       void __iomem *dram_sync;
+};
+
+struct wakeup_src {
+       int irq_nr;
+       char src[10];
+};
+
+struct forced_standby_module {
+       char oh_name[15];
+       struct device *dev;
+};
+
+int wkup_m3_copy_code(const u8 *data, size_t size);
+int wkup_m3_prepare(void);
+void wkup_m3_register_txev_handler(void (*txev_handler)(void));
+
+#endif
+
+#define        IPC_CMD_DS0                     0x3
+#define IPC_CMD_RESET                   0xe
+#define DS_IPC_DEFAULT                 0xffffffff
+#define M3_VERSION_UNKNOWN             0x0000ffff
+#define M3_BASELINE_VERSION            0x21
+
+#define M3_STATE_UNKNOWN               0
+#define M3_STATE_RESET                 1
+#define M3_STATE_INITED                        2
+#define M3_STATE_MSG_FOR_LP            3
+#define M3_STATE_MSG_FOR_RESET         4
+
+#define AM33XX_OCMC_END                        0x40310000
+#define AM33XX_EMIF_BASE               0x4C000000
+
+#define MEM_TYPE_DDR2          2
+
+#endif
arch/arm/mach-omap2/wkup_m3.c new file +183 -1
new file mode 100644
index 0000000..8eaa7f3
@@ -0,0 +1,183 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+
+#include "pm33xx.h"
+#include "control.h"
+#include "omap_device.h"
+#include "soc.h"
+
+struct wkup_m3_context {
+       struct device   *dev;
+       void __iomem    *code;
+       void (*txev_handler)(void);
+};
+
+struct wkup_m3_context *wkup_m3;
+
+int wkup_m3_copy_code(const u8 *data, size_t size)
+{
+       if (size > SZ_16K)
+               return -ENOMEM;
+
+       memcpy_toio(wkup_m3->code, data, size);
+
+       return 0;
+}
+
+
+void wkup_m3_register_txev_handler(void (*txev_handler)(void))
+{
+       wkup_m3->txev_handler = txev_handler;
+}
+
+/* have platforms do what they want in atomic context over here? */
+static irqreturn_t wkup_m3_txev_handler(int irq, void *unused)
+{
+       am33xx_txev_eoi();
+
+       /* callback to be executed in atomic context */
+       /* return 0 implies IRQ_HANDLED else IRQ_NONE */
+       wkup_m3->txev_handler();
+
+       am33xx_txev_enable();
+
+       return IRQ_HANDLED;
+}
+
+int wkup_m3_prepare(void)
+{
+       struct platform_device *pdev = to_platform_device(wkup_m3->dev);
+
+       /* check that the code is loaded */
+       omap_device_deassert_hardreset(pdev, "wkup_m3");
+
+       return 0;
+}
+
+static int wkup_m3_probe(struct platform_device *pdev)
+{
+       int irq, ret = 0;
+       struct resource *mem;
+
+       pm_runtime_enable(&pdev->dev);
+
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+               return ret;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq) {
+               dev_err(wkup_m3->dev, "no irq resource\n");
+               ret = -ENXIO;
+               goto err;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(wkup_m3->dev, "no memory resource\n");
+               ret = -ENXIO;
+               goto err;
+       }
+
+       wkup_m3 = kzalloc(sizeof(*wkup_m3), GFP_KERNEL);
+       if (!wkup_m3) {
+               pr_err("Memory allocation failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       wkup_m3->dev = &pdev->dev;
+
+       wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
+       if (!wkup_m3->code) {
+               dev_err(wkup_m3->dev, "could not ioremap\n");
+               ret = -EADDRNOTAVAIL;
+               goto err;
+       }
+
+       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
+                 IRQF_DISABLED, "wkup_m3_txev", NULL);
+       if (ret) {
+               dev_err(wkup_m3->dev, "request_irq failed\n");
+               goto err;
+       }
+
+err:
+       return ret;
+}
+
+static int wkup_m3_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct of_device_id wkup_m3_dt_ids[] = {
+       { .compatible = "ti,am3353-wkup-m3" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wkup_m3_dt_ids);
+
+static int wkup_m3_rpm_suspend(struct device *dev)
+{
+       return -EBUSY;
+}
+
+static int wkup_m3_rpm_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops wkup_m3_ops = {
+       SET_RUNTIME_PM_OPS(wkup_m3_rpm_suspend, wkup_m3_rpm_resume, NULL)
+};
+
+static struct platform_driver wkup_m3_driver = {
+       .probe          = wkup_m3_probe,
+       .remove         = wkup_m3_remove,
+       .driver         = {
+               .name   = "wkup_m3",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(wkup_m3_dt_ids),
+               .pm     = &wkup_m3_ops,
+       },
+};
+
+static __init int wkup_m3_init(void)
+{
+       return platform_driver_register(&wkup_m3_driver);
+}
+
+static __exit void wkup_m3_exit(void)
+{
+       platform_driver_unregister(&wkup_m3_driver);
+}
+omap_postcore_initcall(wkup_m3_init);
+module_exit(wkup_m3_exit);
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#60 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Signature · 2 lines
Regards,
Nishanth Menon
#61 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

$subject and patch don't match.

Quoted 6 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Regards,
Santosh

#62 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 9 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 6 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 8 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Regards,
Santosh

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

Regards,
Dave

#63 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 25 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 8 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Regards,
Santosh

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

yes, but doing it in M3 will ensure it is a "hardware behavior" - from debug perspective, you could make M3 firmware "release mode" - which it is stringent in terms of forcing all down to target state, OR "debug" where it does nothing - thus helping pick up driver bugs. With M3 in the picture, we now have an awesome flexibility of "defining what the hardware behavior should be" - that allows us to have lesser code to carry in kernel- especially ones(like quirks) that does not really add value from power saving strategies.

Signature · 2 lines
Regards,
Nishanth Menon
#64 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Dave Gerlach
Quoted 25 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 8 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Regards,
Santosh

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

That being said, IMO, the kernel (specifically omap_device) should handle this, and it should be rather easy to do in the omap_device layer and keep the SoC suspend/resume core code simple and ignorant of these "quirks."

AFAICT, there's no reason these quirks need to be dealt with immediatly on suspend. A slight delay should be fine, as long as it's before the next suspend/idle attempt, right?

Given that, what we need to do (and by we, I mean you) is to flag all broken IP blocks, and let omap_device handle them in a suspend/resume notifier (c.f. register_pm_notifier() and PM_POST_SUSPEND.)

That will keep things contained to the omap_device/hwmod level and allow flexiblity for future broken SoCs where the list of broken IP blocks is different. Though surely this broken hardware doesn't exist in AM4xxx because someone noticed this early on and pointed out that it should be fixed in hardware, right? ;)

Kevin

#65 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 30 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

Quoted 8 lines

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all.. tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior. I know it breaks the purity of role, but as the next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Quoted 6 lines

That being said, IMO, the kernel (specifically omap_device) should handle this, and it should be rather easy to do in the omap_device layer and keep the SoC suspend/resume core code simple and ignorant of these "quirks."

Quoted 7 lines

AFAICT, there's no reason these quirks need to be dealt with immediatly on suspend. A slight delay should be fine, as long as it's before the next suspend/idle attempt, right?

Given that, what we need to do (and by we, I mean you) is to flag all broken IP blocks, and let omap_device handle them in a suspend/resume notifier (c.f. register_pm_notifier() and PM_POST_SUSPEND.)

yes - that is the alternate that comes to mind.

Signature · 2 lines
Regards,
Nishanth Menon
#66 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

Quoted 4 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

Quoted 9 lines
Quoted 9 lines

That being said, IMO, the kernel (specifically omap_device) should handle this, and it should be rather easy to do in the omap_device layer and keep the SoC suspend/resume core code simple and ignorant of these "quirks."

AFAICT, there's no reason these quirks need to be dealt with immediatly on suspend. A slight delay should be fine, as long as it's before the next suspend/idle attempt, right?

Quoted 5 lines
Quoted 3 lines

Given that, what we need to do (and by we, I mean you) is to flag all broken IP blocks, and let omap_device handle them in a suspend/resume notifier (c.f. register_pm_notifier() and PM_POST_SUSPEND.)

yes - that is the alternate that comes to mind.

In the earlier reviews of this series (many months ago now), I complained about the presence of this device specific handling in the core MPU PM code. I'm somewhat troubled by the fact that nobody explored alternatives that so easily come to mind.

Kevin

#67 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 59 lines · Kevin Hilman
Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Quoted 3 lines

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

My view is that the M3 should *ignore* the presence/existence of MPU's drivers. M3 will do whatever to force the system to go to suspend once notified - this saves us the prehistoric perpetual trouble when drivers have bugs (which get exposed in weird usage scenarios) in production systems, we dont get any hardware help to fix them up while attempting low power states and system never really hits low power state. This was always because OMAP and it's derivatives have been "democratic" in power management - if every hardware block achieves proper state, then we achieve a system-wide low power state.

Quoted 10 lines
Quoted 5 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

suspend is a very controlled state as against cpuidle where driver knowledge is necessary and in fact mandatory. drivers are supposed to release their resources - and even though we test the hell out of them, we do have paths untrodden when it comes to production systems.

I think the insight we have about the hardware make us(linux folks) want to own the decision making process on the master MPU - I mean, *nobody*(including me) wants to trust a "firmware" - that word is almost synonymous with "unspeakable horror".

If on the other hand, we had a non-programmable hardware which would force all systems to achieve off mode (imagine having a PRCM which was really capable of doing it), we would have probably not had to deal with those pesky "stuck-in-transition" and other variants of issues (where MPU went to low power state, but core refused to go down - resulting in 200mA+ power instead of the <1mA we expected to see).

I consider M3 to power management similar to what Neon is to ARM. I mean, I would even love a PMIC which is completely reprogrammable (where I could define the registers in s/w)!

My personal thought is that (if possible):
a) we should try to make the source firmware visible to everyone who has a stake on it.
b) If (a) is possible, then we should see how we can consider M3 as an extension to Linux power strategy, rather than a "necessary burden" to carry around.

In this particular case. (a) is done see [1]. So, why not (b)? A synergy does not necessarily mean "purity of role" is broken. it is just another way of doing the job.

While, I personally dont think [1] is public enough, we can try to work through those current constraints to ensure everything is synergistic.

in other words, this is not a "Graphics" or "Multimedia" or even few "BIOS" kind of "hidden firmware you cannot do anything about" scenario - here, *we* have the choice.

[1] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=summary

Quoted 14 lines
Quoted 14 lines
Quoted 13 lines

That being said, IMO, the kernel (specifically omap_device) should handle this, and it should be rather easy to do in the omap_device layer and keep the SoC suspend/resume core code simple and ignorant of these "quirks."

AFAICT, there's no reason these quirks need to be dealt with immediatly on suspend. A slight delay should be fine, as long as it's before the next suspend/idle attempt, right?

Given that, what we need to do (and by we, I mean you) is to flag all broken IP blocks, and let omap_device handle them in a suspend/resume notifier (c.f. register_pm_notifier() and PM_POST_SUSPEND.)

Quoted 6 lines
Quoted 1 line

yes - that is the alternate that comes to mind.

In the earlier reviews of this series (many months ago now), I complained about the presence of this device specific handling in the core MPU PM code. I'm somewhat troubled by the fact that nobody explored alternatives that so easily come to mind.

Just spoke to Dave in person a few mins back, and he is going to go through all the previous mail chains and attempt to be thorough again - seems like going through a written list of pending actions completely missed many key aspects of prior reviews :). Apologies on this.

Signature · 2 lines
Regards,
Nishanth Menon
#68 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 85 lines · Nishanth Menon
Quoted 59 lines · Kevin Hilman
Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Quoted 3 lines

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

My view is that the M3 should *ignore* the presence/existence of MPU's drivers. M3 will do whatever to force the system to go to suspend once notified - this saves us the prehistoric perpetual trouble when drivers have bugs (which get exposed in weird usage scenarios) in production systems, we dont get any hardware help to fix them up while attempting low power states and system never really hits low power state. This was always because OMAP and it's derivatives have been "democratic" in power management - if every hardware block achieves proper state, then we achieve a system-wide low power state.

Quoted 10 lines
Quoted 5 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

Quoted 4 lines

suspend is a very controlled state as against cpuidle where driver knowledge is necessary and in fact mandatory. drivers are supposed to release their resources - and even though we test the hell out of them, we do have paths untrodden when it comes to production systems.

Since folks don't seem to care about idle for AM33xx (starting with the hw designers, from what I can tell), you have the luxury of thinking only about suspend, where firmware can be heavy handed and force things into submission. Unfortunately, with cpuidle, life is not that easy and you have to have cooperation of the device drivers. Coordinating that with firmware is not so simple, to put it mildly.

Any SW/firmware design that does not account for *both* static PM (suspend/resume) and dynamic PM (runtime PM + CPUidle) is not long-term maintainable, and thus ready for mainline IMO. (BTW, this is another theme from previous reviews of this series.)

Quoted 58 lines

I think the insight we have about the hardware make us(linux folks) want to own the decision making process on the master MPU - I mean, *nobody*(including me) wants to trust a "firmware" - that word is almost synonymous with "unspeakable horror".

If on the other hand, we had a non-programmable hardware which would force all systems to achieve off mode (imagine having a PRCM which was really capable of doing it), we would have probably not had to deal with those pesky "stuck-in-transition" and other variants of issues (where MPU went to low power state, but core refused to go down - resulting in 200mA+ power instead of the <1mA we expected to see).

I consider M3 to power management similar to what Neon is to ARM. I mean, I would even love a PMIC which is completely reprogrammable (where I could define the registers in s/w)!

My personal thought is that (if possible):
a) we should try to make the source firmware visible to everyone who has a stake on it.
b) If (a) is possible, then we should see how we can consider M3 as an extension to Linux power strategy, rather than a "necessary burden" to carry around.

In this particular case. (a) is done see [1]. So, why not (b)? A synergy does not necessarily mean "purity of role" is broken. it is just another way of doing the job.

While, I personally dont think [1] is public enough, we can try to work through those current constraints to ensure everything is synergistic.

in other words, this is not a "Graphics" or "Multimedia" or even few "BIOS" kind of "hidden firmware you cannot do anything about" scenario -
here, *we* have the choice.

[1] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=summary

Quoted 14 lines
Quoted 14 lines
Quoted 13 lines

That being said, IMO, the kernel (specifically omap_device) should handle this, and it should be rather easy to do in the omap_device layer and keep the SoC suspend/resume core code simple and ignorant of these "quirks."

AFAICT, there's no reason these quirks need to be dealt with immediatly on suspend. A slight delay should be fine, as long as it's before the next suspend/idle attempt, right?

Given that, what we need to do (and by we, I mean you) is to flag all broken IP blocks, and let omap_device handle them in a suspend/resume notifier (c.f. register_pm_notifier() and PM_POST_SUSPEND.)

Quoted 6 lines
Quoted 1 line

yes - that is the alternate that comes to mind.

In the earlier reviews of this series (many months ago now), I complained about the presence of this device specific handling in the core MPU PM code. I'm somewhat troubled by the fact that nobody explored alternatives that so easily come to mind.

Quoted 5 lines

Just spoke to Dave in person a few mins back, and he is going to go through all the previous mail chains and attempt to be thorough again -
seems like going through a written list of pending actions completely missed many key aspects of prior reviews :). Apologies on this.

Thanks.

Since he's inherited this series Dave gets a get out of jail free card... this time. Next time, I expect I might be grumpier.

Kevin

#69 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 99 lines · Kevin Hilman
Quoted 85 lines · Nishanth Menon
Quoted 59 lines · Kevin Hilman
Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Quoted 3 lines

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

My view is that the M3 should *ignore* the presence/existence of MPU's drivers. M3 will do whatever to force the system to go to suspend once notified - this saves us the prehistoric perpetual trouble when drivers have bugs (which get exposed in weird usage scenarios) in production systems, we dont get any hardware help to fix them up while attempting low power states and system never really hits low power state. This was always because OMAP and it's derivatives have been "democratic" in power management - if every hardware block achieves proper state, then we achieve a system-wide low power state.

Quoted 10 lines
Quoted 5 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

Quoted 4 lines

suspend is a very controlled state as against cpuidle where driver knowledge is necessary and in fact mandatory. drivers are supposed to release their resources - and even though we test the hell out of them, we do have paths untrodden when it comes to production systems.

Since folks don't seem to care about idle for AM33xx (starting with the hw designers, from what I can tell), you have the luxury of thinking only about suspend, where firmware can be heavy handed and force things into submission. Unfortunately, with cpuidle, life is not that easy and you have to have cooperation of the device drivers. Coordinating that with firmware is not so simple, to put it mildly.

Quoted 4 lines

Any SW/firmware design that does not account for *both* static PM (suspend/resume) and dynamic PM (runtime PM + CPUidle) is not long-term maintainable, and thus ready for mainline IMO. (BTW, this is another theme from previous reviews of this series.)

I completely agree with you. But is'nt the specific suspend state we are attempting to achieve on AM335x just tooo expensive latency wise for being even considered for cpuidle? I am sure you recollect the latencies involved in OMAP3 OFF mode Vs OMAP4+ OFF mode - which basically kicked out OFF mode from OMAP4 cpuidle C states? - it was practically useless

in this *specific* power state we are attempting, we do a bunch of i2c operations, etc, in short something that cannot even be considered for cpuidle.

Considering this, we can consider the same only for suspend path - hence allowing firmware to do more here.

This does not conflict with cpuidle (which controls MPU) or runtime PM (which kicks in once you have drivers active, but if drivers get active, we dont need to deal with this crap).

Dont you think this helps the specific case to move this into firmware rather than into omap_device?
[...]

Signature · 2 lines
Regards,
Nishanth Menon
#70 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 121 lines · Nishanth Menon
Quoted 99 lines · Kevin Hilman
Quoted 85 lines · Nishanth Menon
Quoted 59 lines · Kevin Hilman
Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Quoted 3 lines

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

My view is that the M3 should *ignore* the presence/existence of MPU's drivers. M3 will do whatever to force the system to go to suspend once notified - this saves us the prehistoric perpetual trouble when drivers have bugs (which get exposed in weird usage scenarios) in production systems, we dont get any hardware help to fix them up while attempting low power states and system never really hits low power state. This was always because OMAP and it's derivatives have been "democratic" in power management - if every hardware block achieves proper state, then we achieve a system-wide low power state.

Quoted 10 lines
Quoted 5 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

Quoted 4 lines

suspend is a very controlled state as against cpuidle where driver knowledge is necessary and in fact mandatory. drivers are supposed to release their resources - and even though we test the hell out of them, we do have paths untrodden when it comes to production systems.

Since folks don't seem to care about idle for AM33xx (starting with the hw designers, from what I can tell), you have the luxury of thinking only about suspend, where firmware can be heavy handed and force things into submission. Unfortunately, with cpuidle, life is not that easy and you have to have cooperation of the device drivers. Coordinating that with firmware is not so simple, to put it mildly.

Quoted 4 lines

Any SW/firmware design that does not account for *both* static PM (suspend/resume) and dynamic PM (runtime PM + CPUidle) is not long-term maintainable, and thus ready for mainline IMO. (BTW, this is another theme from previous reviews of this series.)

I completely agree with you. But is'nt the specific suspend state we are attempting to achieve on AM335x just tooo expensive latency wise for being even considered for cpuidle?

I am sure you recollect the latencies involved in OMAP3 OFF mode Vs OMAP4+ OFF mode - which basically kicked out OFF mode from OMAP4 cpuidle C states? - it was practically useless

in this *specific* power state we are attempting, we do a bunch of i2c operations, etc, in short something that cannot even be considered for cpuidle.

Considering this, we can consider the same only for suspend path - hence allowing firmware to do more here.

Quoted 6 lines

This does not conflict with cpuidle (which controls MPU) or runtime PM (which kicks in once you have drivers active, but if drivers get active, we dont need to deal with this crap).

Dont you think this helps the specific case to move this into firmware rather than into omap_device?

No, I don't.

That means the firmware design is based on several assumptions about what Linux can and can't do in idle, and then imposing that on future Linux designs as well. I dont' buy it.

Kevin

#71 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 127 lines · Kevin Hilman
Quoted 125 lines · Nishanth Menon
Quoted 99 lines · Kevin Hilman
Quoted 85 lines · Nishanth Menon
Quoted 59 lines · Kevin Hilman
Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Quoted 3 lines

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

My view is that the M3 should *ignore* the presence/existence of MPU's drivers. M3 will do whatever to force the system to go to suspend once notified - this saves us the prehistoric perpetual trouble when drivers have bugs (which get exposed in weird usage scenarios) in production systems, we dont get any hardware help to fix them up while attempting low power states and system never really hits low power state. This was always because OMAP and it's derivatives have been "democratic" in power management - if every hardware block achieves proper state, then we achieve a system-wide low power state.

Quoted 10 lines
Quoted 5 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

Quoted 4 lines

suspend is a very controlled state as against cpuidle where driver knowledge is necessary and in fact mandatory. drivers are supposed to release their resources - and even though we test the hell out of them, we do have paths untrodden when it comes to production systems.

Since folks don't seem to care about idle for AM33xx (starting with the hw designers, from what I can tell), you have the luxury of thinking only about suspend, where firmware can be heavy handed and force things into submission. Unfortunately, with cpuidle, life is not that easy and you have to have cooperation of the device drivers. Coordinating that with firmware is not so simple, to put it mildly.

Quoted 4 lines

Any SW/firmware design that does not account for *both* static PM (suspend/resume) and dynamic PM (runtime PM + CPUidle) is not long-term maintainable, and thus ready for mainline IMO. (BTW, this is another theme from previous reviews of this series.)

I completely agree with you. But is'nt the specific suspend state we are attempting to achieve on AM335x just tooo expensive latency wise for being even considered for cpuidle?

I am sure you recollect the latencies involved in OMAP3 OFF mode Vs OMAP4+ OFF mode - which basically kicked out OFF mode from OMAP4 cpuidle C states? - it was practically useless

in this *specific* power state we are attempting, we do a bunch of i2c operations, etc, in short something that cannot even be considered for cpuidle.

Considering this, we can consider the same only for suspend path - hence allowing firmware to do more here.

This does not conflict with cpuidle (which controls MPU) or runtime PM (which kicks in once you have drivers active, but if drivers get active, we dont need to deal with this crap).

Quoted 8 lines
Quoted 2 lines

Dont you think this helps the specific case to move this into firmware rather than into omap_device?

No, I don't.

That means the firmware design is based on several assumptions about what Linux can and can't do in idle, and then imposing that on future Linux designs as well. I dont' buy it.

OK, I back out my proposal. Will let Dave try out a generic solution in kernel and comment back.

Signature · 2 lines
Regards,
Nishanth Menon
#72 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Kevin Hilman
Quoted 130 lines · Kevin Hilman
Quoted 121 lines · Nishanth Menon
Quoted 99 lines · Kevin Hilman
Quoted 85 lines · Nishanth Menon
Quoted 59 lines · Kevin Hilman
Quoted 36 lines · Nishanth Menon
Quoted 35 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach
Quoted 15 lines · Santosh Shilimkar

$subject and patch don't match.

Quoted 4 lines · Nishanth Menon
Quoted 3 lines · Russ Dill

In reference to
the M3 handling it, the M3 wouldn't know which devices have a driver bound and which don't.

Quoted 8 lines

Does it need to? M3 firmware can pretty much define "I will force the device into low power state, and if the drivers dont handle things properly, fix the darned driver". M3 behavior should be considered as a "hardware" as far as Linux running on MPU is concerned, and firmware helps change the behavior by accounting for SoC quirks. *if* we have ability to handle this in the firmware, there is no need to carry this in Linux.

Quoted 4 lines

I agree with Nishant. I don't like this patch and IIRC, I gave same comment in the last version. Linux need not know about all such firmware quirks. Also all these M3 specific stuff, should be done somewhere else. Probably having a small M3 driver won't be a bad idea.

Quoted 6 lines

I am not opposed to doing it this way and letting the M3 firmware handle idling these modules, however the one concern raised in the last series is that an approach that does not acknowledge drivers will hide driver PM bugs. I suppose as long as I make sure to document that the devices are being idled by the M3 firmware this may not be an issue. I will look into implementing this.

No, please don't start idling devices in firmware that are otherwise managed by Linux. Keep the firmware simple and dumb. Linux is managing these devices, it should manage their bugs too.

Quoted 8 lines
Quoted 3 lines

This is not just about idling devices. This is about handling broken IP blocks whose power-on reset state does not allow the the powerdomain to reach its target state. That's just bad hardware design.

Right, this is where M3 can help -> provide a consistent state for linux kernel to work with. by the fact that we want to keep majority of the power code inside master CPU, we are just letting M3 help us with nothing major at all..

heh, I would say HW design bugs like this are more than "nothing major at all." :)

Quoted 2 lines

tiny stuff like these can help "fix" the hardware design quirks by hiding it behind the firmware and modifying the hardware behavior.

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Quoted 3 lines

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

My view is that the M3 should *ignore* the presence/existence of MPU's drivers. M3 will do whatever to force the system to go to suspend once notified - this saves us the prehistoric perpetual trouble when drivers have bugs (which get exposed in weird usage scenarios) in production systems, we dont get any hardware help to fix them up while attempting low power states and system never really hits low power state. This was always because OMAP and it's derivatives have been "democratic" in power management - if every hardware block achieves proper state, then we achieve a system-wide low power state.

Quoted 10 lines
Quoted 5 lines

I know it breaks the purity of role, but as the
next evolution, we might want to consider M3 something like an "accelerator" for power management activity.. (not saying it is that fast.. but conceptually).

Yes, it breaks the purity of role, and makes it hard to maintain and extend to future SoCs. As a maintainer, that's a red flag. IMO, the roles need to be kept clear. The M3 manages some devices and the interconnect that MPU/Linux cannot, the rest are managed by Linux.

Quoted 4 lines

suspend is a very controlled state as against cpuidle where driver knowledge is necessary and in fact mandatory. drivers are supposed to release their resources - and even though we test the hell out of them, we do have paths untrodden when it comes to production systems.

Since folks don't seem to care about idle for AM33xx (starting with the hw designers, from what I can tell), you have the luxury of thinking only about suspend, where firmware can be heavy handed and force things into submission. Unfortunately, with cpuidle, life is not that easy and you have to have cooperation of the device drivers. Coordinating that with firmware is not so simple, to put it mildly.

Quoted 4 lines

Any SW/firmware design that does not account for *both* static PM (suspend/resume) and dynamic PM (runtime PM + CPUidle) is not long-term maintainable, and thus ready for mainline IMO. (BTW, this is another theme from previous reviews of this series.)

I completely agree with you. But is'nt the specific suspend state we are attempting to achieve on AM335x just tooo expensive latency wise for being even considered for cpuidle?

I am sure you recollect the latencies involved in OMAP3 OFF mode Vs OMAP4+ OFF mode - which basically kicked out OFF mode from OMAP4 cpuidle C states? - it was practically useless

in this *specific* power state we are attempting, we do a bunch of i2c operations, etc, in short something that cannot even be considered for cpuidle.

Considering this, we can consider the same only for suspend path - hence allowing firmware to do more here.

Quoted 6 lines

This does not conflict with cpuidle (which controls MPU) or runtime PM (which kicks in once you have drivers active, but if drivers get active, we dont need to deal with this crap).

Dont you think this helps the specific case to move this into firmware rather than into omap_device?

Quoted 7 lines

No, I don't.

That means the firmware design is based on several assumptions about what Linux can and can't do in idle, and then imposing that on future Linux designs as well. I dont' buy it.

Kevin

I was taking a look at this situation, figuring that the suspend/resume callbacks in omap_device might be the right place to do it, and came across this:

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=72bb6f9b51c82c820ddef892455a85b115460904

Under what situations would the driver callbacks be present if probe fails? I'm looking at really_probe in drivers/base/dd.c, and if probe fails, dev->driver is set to NULL. What was the condition this was protecting against?

Also, by modifying _od_suspend_noirq, can we force idle unbound omap device? Would we need a new omap_hwmod flag to check which devices should be force idled if no driver is bound?

#73 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Hi Russ,

Russ Dill <[email protected]> writes:

[...]

Quoted 10 lines

I was taking a look at this situation, figuring that the suspend/resume callbacks in omap_device might be the right place to do it, and came across this:

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=72bb6f9b51c82c820ddef892455a85b115460904

Under what situations would the driver callbacks be present if probe fails? I'm looking at really_probe in drivers/base/dd.c, and if probe fails, dev->driver is set to NULL. What was the condition this was protecting against?

The static suspend/resume methods for PM domains don't check for dev->driver. (c.f. device_resume_noirq()), so during system suspend, the PM domain callbacks are called whether or not there is a driver.

A simlar fix could've been done by checking for the existence of dev->driver (and maybe that's a better solution), but I chose the latter so omap_device has a finer grained track of the driver status.

Quoted 3 lines

Also, by modifying _od_suspend_noirq, can we force idle unbound omap device? Would we need a new omap_hwmod flag to check which devices should be force idled if no driver is bound?

I suppose you could, but that would probably mask driver bugs where the driver is not properly runtime suspending itself before being removed.

Kevin

#74 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Kevin Hilman

(picking up an old thread, again)

Quoted 11 lines · Kevin Hilman

I disagree here. I'm a firmware minimalist, and hiding bugs like this in the firmware is wrong when Linux is otherwise managing these devices. It also imposes criteria on the firmware of future SoCs that doesn't belong there either. IMO, the only stuff the firmware should do is what Linux *cannot* do.

Remember, this only needs to happen when there isn't a driver for these devices. Should we communicate to the firmware that the OS has no driver, so please enable the hack? I think not.

Agreed on not hiding the bugs in the firmware. Moreover, M3 can't access the IPs in PER domain which is where the bad modules are, so the h/w doesn't support such hackery (+1 for the h/w after all the -1's that it gets ;)

[...]

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines

That being said, IMO, the kernel (specifically omap_device) should handle this, and it should be rather easy to do in the omap_device layer and keep the SoC suspend/resume core code simple and ignorant of these "quirks."

AFAICT, there's no reason these quirks need to be dealt with immediatly on suspend. A slight delay should be fine, as long as it's before the next suspend/idle attempt, right?

Given that, what we need to do (and by we, I mean you) is to flag all broken IP blocks, and let omap_device handle them in a suspend/resume notifier (c.f. register_pm_notifier() and PM_POST_SUSPEND.)

Quoted 7 lines
Quoted 1 line

yes - that is the alternate that comes to mind.

In the earlier reviews of this series (many months ago now), I complained about the presence of this device specific handling in the core MPU PM code. I'm somewhat troubled by the fact that nobody explored alternatives that so easily come to mind.

My bad. I was thinking along those lines [1] but after the suggestion on using the driver bound status i just went with that suggestion in the dumbest possible manner.

Regards,
Vaibhav

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2012-November/129676.html

#75 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Kevin Hilman

Hi folks,

catching up on this thread.

Quoted 15 lines · Dave Gerlach
arch/arm/mach-omap2/pm33xx.c new file +15 -0
+
+static int am33xx_pm_suspend(void)
+{
+     int i, j, ret = 0;
+
+     int status = 0;
+     struct platform_device *pdev;
+     struct omap_device *od;
+
+     /*
+      * By default the following IPs do not have MSTANDBY asserted
+      * which is necessary for PER domain transition. If the drivers
+      * are not compiled into the kernel HWMOD code will not change the
+      * state of the IPs if the IP was not never enabled. To ensure
+      * that there no issues with or without the drivers being compiled

arch/arm/mach-omap2/pm33xx.c line 117

Quoted 10 lines
arch/arm/mach-omap2/pm33xx.c new file +10 -0
+      * in the kernel, we forcefully put these IPs to idle.
+      */
+     for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+             pdev = to_platform_device(am33xx_mod[i].dev);
+             od = to_omap_device(pdev);
+             if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+                     omap_device_enable_hwmods(od);
+                     omap_device_idle_hwmods(od);
+             }
+     }

Does this have to be done for every suspend entry, or can it just be done once during kernel initialization?

If the latter, shouldn't this be done by hwmod during the initial reset and idle of all of these devices, based on a flag? For example, we had this flag for OMAP3630:

* HWMOD_FORCE_MSTANDBY: Always keep MIDLEMODE bits cleared so that device
* is kept in force-standby mode. Failing to do so causes PM problems
* with musb on OMAP3630 at least. Note that musb has a dedicated
register
* to control MSTANDBY signal when MIDLEMODE is set to force-standby.

- Paul

#76 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 40 lines · Paul Walmsley

Hi folks,

catching up on this thread.

Quoted 15 lines · Dave Gerlach
(quoted diff) +15 -0
+
+static int am33xx_pm_suspend(void)
+{
+     int i, j, ret = 0;
+
+     int status = 0;
+     struct platform_device *pdev;
+     struct omap_device *od;
+
+     /*
+      * By default the following IPs do not have MSTANDBY asserted
+      * which is necessary for PER domain transition. If the drivers
+      * are not compiled into the kernel HWMOD code will not change the
+      * state of the IPs if the IP was not never enabled. To ensure
+      * that there no issues with or without the drivers being compiled

Review

Quoted 10 lines
(quoted diff) +10 -0
+      * in the kernel, we forcefully put these IPs to idle.
+      */
+     for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+             pdev = to_platform_device(am33xx_mod[i].dev);
+             od = to_omap_device(pdev);
+             if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+                     omap_device_enable_hwmods(od);
+                     omap_device_idle_hwmods(od);
+             }
+     }

Does this have to be done for every suspend entry, or can it just be done once during kernel initialization?

If the latter, shouldn't this be done by hwmod during the initial reset and idle of all of these devices, based on a flag? For example, we had this flag for OMAP3630:

Quoted 6 lines

* HWMOD_FORCE_MSTANDBY: Always keep MIDLEMODE bits cleared so that device
* is kept in force-standby mode. Failing to do so causes PM problems
* with musb on OMAP3630 at least. Note that musb has a dedicated
register
* to control MSTANDBY signal when MIDLEMODE is set to force-standby.

Hi,
Unfortunately this does have to be done at some point after every suspend/resume cycle because while the IPs are idled during initial reset, after a suspend cycle the context loss when no driver is bound causes MSTANDBY to be unasserted again which as mentioned breaks the PER power domain transition during the next suspend attempt.

The current plan for this is somewhat similar to what you mentioned, all of the troublesome modules will be flagged in hwmod and when the hwmods are loaded they are tracked if no driver gets bound and then idled post resume by a pm_notifier.

Regards,
Dave

Quoted 7 lines

- Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#77 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Dave Gerlach
Quoted 728 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

AM335x supports various low power modes as documented in section 8.1.4.3 of the AM335x TRM which is available @ http://www.ti.com/litv/pdf/spruh73f

DeepSleep0 mode offers the lowest power mode with limited wakeup sources without a system reboot and is mapped as the suspend state in the kernel. In this state, MPU and PER domains are turned off with the internal RAM held in retention to facilitate resume process. As part of the boot process, the assembly code is copied over to OCMCRAM using the OMAP SRAM code.

AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU in DeepSleep0 entry and exit. WKUP_M3 takes care of the clockdomain and powerdomain transitions based on the intended low power state. MPU needs to load the appropriate WKUP_M3 binary onto the WKUP_M3 memory space before it can leverage any of the PM features like DeepSleep.

The IPC mechanism between MPU and WKUP_M3 uses a mailbox sub-module and 8 IPC registers in the Control module. MPU uses the assigned Mailbox for issuing an interrupt to WKUP_M3 which then goes and checks the IPC registers for the payload. WKUP_M3 has the ability to trigger on interrupt to MPU by executing the "sev" instruction.

In the current implementation when the suspend process is initiated MPU interrupts the WKUP_M3 to let it know about the intent of entering DeepSleep0 and waits for an ACK. When the ACK is received MPU continues with its suspend process to suspend all the drivers and then jumps to assembly in OCMC RAM. The assembly code puts the PLLs in bypass, puts the external RAM in self-refresh mode and then finally execute the WFI instruction. Execution of the WFI instruction triggers another interrupt to the WKUP_M3 which then continues wiht the power down sequence wherein the clockdomain and powerdomain transition takes place. As part of the sleep sequence, WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI execution on WKUP_M3 causes the hardware to disable the main oscillator of the SoC.

When a wakeup event occurs, WKUP_M3 starts the power-up sequence by switching on the power domains and finally enabling the clock to MPU. Since the MPU gets powered down as part of the sleep sequence in the resume path ROM code starts executing. The ROM code detects a wakeup from sleep and then jumps to the resume location in OCMC which was populated in one of the IPC registers as part of the suspend sequence.

The low level code in OCMC relocks the PLLs, enables access to external RAM and then jumps to the cpu_resume code of the kernel to finish the resume process.

Cc Tony Lingren <[email protected]>
Cc Santosh Shilimkar <[email protected]>
Cc Benoit Cousson <[email protected]>
Cc Paul Walmsley <[email protected]>
Cc Kevin Hilman <[email protected]>
---
 arch/arm/mach-omap2/pm33xx.c  |  474 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h  |   77 +++++++
 arch/arm/mach-omap2/wkup_m3.c |  183 ++++++++++++++++
 3 files changed, 734 insertions(+)
 create mode 100644 arch/arm/mach-omap2/pm33xx.c
 create mode 100644 arch/arm/mach-omap2/pm33xx.h
 create mode 100644 arch/arm/mach-omap2/wkup_m3.c
arch/arm/mach-omap2/pm33xx.c new file +474 -0
new file mode 100644
index 0000000..d291c76
@@ -0,0 +1,474 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ti_emif.h>
+#include <linux/omap-mailbox.h>
+
+#include <asm/suspend.h>
+#include <asm/proc-fns.h>
+#include <asm/sizes.h>
+#include <asm/fncpy.h>
+#include <asm/system_misc.h>
+
+#include "pm.h"
+#include "cm33xx.h"
+#include "pm33xx.h"
+#include "control.h"
+#include "common.h"
+#include "clockdomain.h"
+#include "powerdomain.h"
+#include "omap_hwmod.h"
+#include "omap_device.h"
+#include "soc.h"
+#include "sram.h"
+
+static void __iomem *am33xx_emif_base;
+static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
+static struct clockdomain *gfx_l4ls_clkdm;
+
+struct wakeup_src wakeups[] = {
+       {.irq_nr = 35,  .src = "USB0_PHY"},
+       {.irq_nr = 36,  .src = "USB1_PHY"},
+       {.irq_nr = 40,  .src = "I2C0"},
+       {.irq_nr = 41,  .src = "RTC Timer"},
+       {.irq_nr = 42,  .src = "RTC Alarm"},
+       {.irq_nr = 43,  .src = "Timer0"},
+       {.irq_nr = 44,  .src = "Timer1"},
+       {.irq_nr = 45,  .src = "UART"},
+       {.irq_nr = 46,  .src = "GPIO0"},
+       {.irq_nr = 48,  .src = "MPU_WAKE"},
+       {.irq_nr = 49,  .src = "WDT0"},
+       {.irq_nr = 50,  .src = "WDT1"},
+       {.irq_nr = 51,  .src = "ADC_TSC"},
+};
+
+struct forced_standby_module am33xx_mod[] = {
+       {.oh_name = "usb_otg_hs"},
+       {.oh_name = "tptc0"},
+       {.oh_name = "tptc1"},
+       {.oh_name = "tptc2"},
+       {.oh_name = "cpgmac0"},
+};
+
+static struct am33xx_pm_context *am33xx_pm;
+
+static DECLARE_COMPLETION(am33xx_pm_sync);
+
+static void (*am33xx_do_wfi_sram)(struct am33xx_suspend_params *);
+
+static struct am33xx_suspend_params susp_params;
+
+#ifdef CONFIG_SUSPEND
+
+static int am33xx_do_sram_idle(long unsigned int unused)
+{
+       am33xx_do_wfi_sram(&susp_params);
+       return 0;
+}
+
+static int am33xx_pm_suspend(void)
+{
+       int i, j, ret = 0;
+
+       int status = 0;
+       struct platform_device *pdev;
+       struct omap_device *od;
+
+       /*
+        * By default the following IPs do not have MSTANDBY asserted
+        * which is necessary for PER domain transition. If the drivers
+        * are not compiled into the kernel HWMOD code will not change the
+        * state of the IPs if the IP was not never enabled. To ensure
+        * that there no issues with or without the drivers being compiled
+        * in the kernel, we forcefully put these IPs to idle.
+        */
+       for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++) {
+               pdev = to_platform_device(am33xx_mod[i].dev);
+               od = to_omap_device(pdev);
+               if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
+                       omap_device_enable_hwmods(od);
+                       omap_device_idle_hwmods(od);
+               }
+       }
+
+       /* Try to put GFX to sleep */
+       omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
+       ret = cpu_suspend(0, am33xx_do_sram_idle);
+
+       status = pwrdm_read_prev_pwrst(gfx_pwrdm);
+       if (status != PWRDM_POWER_OFF)
+               pr_err("PM: GFX domain did not transition\n");
+       else
+               pr_info("PM: GFX domain entered low power state\n");
+
+       /*
+        * BUG: GFX_L4LS clock domain needs to be woken up to
+        * ensure thet L4LS clock domain does not get stuck in transition
+        * If that happens L3 module does not get disabled, thereby leading
+        * to PER power domain transition failing
+        */
+       clkdm_wakeup(gfx_l4ls_clkdm);
+       clkdm_sleep(gfx_l4ls_clkdm);
+
+       if (ret) {
+               pr_err("PM: Kernel suspend failure\n");
+       } else {
+               i = am33xx_pm_status();
+               switch (i) {
+               case 0:
+                       pr_info("PM: Successfully put all powerdomains to target state\n");
+
+                       /*
+                        * The PRCM registers on AM335x do not contain previous state
+                        * information like those present on OMAP4 so we must manually
+                        * indicate transition so state counters are properly incremented
+                        */
+                       pwrdm_post_transition(mpu_pwrdm);
+                       pwrdm_post_transition(per_pwrdm);
+                       break;
+               case 1:
+                       pr_err("PM: Could not transition all powerdomains to target state\n");
+                       ret = -1;
+                       break;
+               default:
+                       pr_err("PM: CM3 returned unknown result :(\nStatus = %d\n", i);
+                       ret = -1;
+               }
+
+               /* print the wakeup reason */
+               i = am33xx_pm_wake_src();
+               for (j = 0; j < ARRAY_SIZE(wakeups); j++) {
+                       if (wakeups[j].irq_nr == i) {
+                               pr_info("PM: Wakeup source %s\n", wakeups[j].src);
+                               break;
+                       }
+               }
+
+               if (j == ARRAY_SIZE(wakeups))
+                       pr_info("PM: Unknown wakeup source %d!\n", i);
+       }
+
+       return ret;
+}
+
+static int am33xx_pm_enter(suspend_state_t suspend_state)
+{
+       int ret = 0;
+
+       switch (suspend_state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = am33xx_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/* returns the error code from msg_send - 0 for success, failure otherwise */
+static int am33xx_ping_wkup_m3(void)
+{
+       int ret = 0;
+
+       /*
+        * Write a dummy message to the mailbox in order to trigger the RX
+        * interrupt to alert the M3 that data is available in the IPC
+        * registers.
+        */
+       ret = omap_mbox_msg_send(am33xx_pm->mbox, 0xABCDABCD);
+
+       return ret;
+}
+
+static void am33xx_m3_state_machine_reset(void)
+{
+       int i;
+
+       am33xx_pm->ipc.sleep_mode = IPC_CMD_RESET;
+
+       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
+
+       am33xx_pm->state = M3_STATE_MSG_FOR_RESET;
+
+       pr_info("PM: Sending message for resetting M3 state machine\n");
+
+       if (!am33xx_ping_wkup_m3()) {
+               i = wait_for_completion_timeout(&am33xx_pm_sync,
+                                       msecs_to_jiffies(500));
+               if (WARN(i == 0, "PM: MPU<->CM3 sync failure\n"))
+                       am33xx_pm->state = M3_STATE_UNKNOWN;
+       } else {
+               pr_warn("PM: Unable to ping CM3\n");
+       }
+}
+
+static int am33xx_pm_begin(suspend_state_t state)
+{
+       int i;
+
+       cpu_idle_poll_ctrl(true);
+
+       am33xx_pm->ipc.sleep_mode       = IPC_CMD_DS0;
+       am33xx_pm->ipc.param1           = DS_IPC_DEFAULT;
+       am33xx_pm->ipc.param2           = DS_IPC_DEFAULT;
+
+       am33xx_pm_ipc_cmd(&am33xx_pm->ipc);
+
+       am33xx_pm->state = M3_STATE_MSG_FOR_LP;
+
+       pr_info("PM: Sending message for entering DeepSleep mode\n");
+
+       if (!am33xx_ping_wkup_m3()) {
+               i = wait_for_completion_timeout(&am33xx_pm_sync,
+                                       msecs_to_jiffies(500));
+               if (WARN(i == 0, "PM: MPU<->CM3 sync failure\n"))
+                       return -1;
+       } else {
+               pr_warn("PM: Unable to ping CM3\n");
+       }
+
+       return 0;
+}
+
+static void am33xx_pm_end(void)
+{
+       am33xx_m3_state_machine_reset();
+
+       cpu_idle_poll_ctrl(false);
+
+       return;
+}
+
+static struct platform_suspend_ops am33xx_pm_ops = {
+       .begin          = am33xx_pm_begin,
+       .end            = am33xx_pm_end,
+       .enter          = am33xx_pm_enter,
+};
+
+/*
+ * Dummy notifier for the mailbox
+ */
+
+static int wkup_mbox_msg(struct notifier_block *self, unsigned long len,
+               void *msg)
+{
+       return 0;
+}
+
+static struct notifier_block wkup_mbox_notifier = {
+       .notifier_call = wkup_mbox_msg,
+};
+
+void am33xx_txev_handler(void)
+{
+       switch (am33xx_pm->state) {
+       case M3_STATE_RESET:
+               am33xx_pm->state = M3_STATE_INITED;
+               am33xx_pm->ver = am33xx_pm_version_get();
+               if (am33xx_pm->ver == M3_VERSION_UNKNOWN ||
+                       am33xx_pm->ver < M3_BASELINE_VERSION) {
+                       pr_warn("PM: CM3 Firmware Version %x not supported\n",
+                                               am33xx_pm->ver);
+               } else {
+                       pr_info("PM: CM3 Firmware Version = 0x%x\n",
+                                               am33xx_pm->ver);
+                       am33xx_pm_ops.valid = suspend_valid_only_mem;
+               }
+               break;
+       case M3_STATE_MSG_FOR_RESET:
+               am33xx_pm->state = M3_STATE_INITED;
+               complete(&am33xx_pm_sync);
+               break;
+       case M3_STATE_MSG_FOR_LP:
+               complete(&am33xx_pm_sync);
+               break;
+       case M3_STATE_UNKNOWN:
+               pr_warn("PM: Unknown CM3 State\n");
+       }
+
+       return;
+}
+
+static void am33xx_pm_firmware_cb(const struct firmware *fw, void *context)
+{
+       struct am33xx_pm_context *am33xx_pm = context;
+       int ret = 0;
+
+       /* no firmware found */
+       if (!fw) {
+               pr_err("PM: request_firmware failed\n");
+               return;
+       }
+
+       wkup_m3_copy_code(fw->data, fw->size);
+
+       wkup_m3_register_txev_handler(am33xx_txev_handler);
+
+       pr_info("PM: Copied the M3 firmware to UMEM\n");
+
+       /*
+        * Invalidate M3 firmware version before hardreset.
+        * Write invalid version in lower 4 nibbles of parameter
+        * register (ipc_regs + 0x8).
+        */
+       am33xx_pm_version_clear();
+
+       am33xx_pm->state = M3_STATE_RESET;
+
+       ret = wkup_m3_prepare();
+       if (ret) {
+               pr_err("PM: Could not prepare WKUP_M3\n");
+               return;
+       }
+
+       /* Physical resume address to be used by ROM code */
+       am33xx_pm->ipc.resume_addr = (AM33XX_OCMC_END -
+               am33xx_do_wfi_sz + am33xx_resume_offset + 0x4);
+
+       am33xx_pm->mbox = omap_mbox_get("wkup_m3", &wkup_mbox_notifier);
+
+       if (IS_ERR(am33xx_pm->mbox)) {
+               ret = -EBUSY;
+               pr_err("PM: IPC Request for A8->M3 Channel failed!\n");
+               return;
+       } else {
+               suspend_set_ops(&am33xx_pm_ops);
+       }
+
+       return;
+}
+
+#endif /* CONFIG_SUSPEND */
+
+/*
+ * Push the minimal suspend-resume code to SRAM
+ */
+void am33xx_push_sram_idle(void)
+{
+       am33xx_do_wfi_sram = (void *)omap_sram_push
+                                       (am33xx_do_wfi, am33xx_do_wfi_sz);
+}
+
+static int __init am33xx_map_emif(void)
+{
+       am33xx_emif_base = ioremap(AM33XX_EMIF_BASE, SZ_32K);
+
+       if (!am33xx_emif_base)
+               return -ENOMEM;
+
+       return 0;
+}
+
+int __init am33xx_pm_init(void)
+{
+       int ret;
+       u32 temp;
+       struct device_node *np;
+       int i;
+
+       if (!soc_is_am33xx())
+               return -ENODEV;
+
+       pr_info("Power Management for AM33XX family\n");
+
+       /*
+        * By default the following IPs do not have MSTANDBY asserted
+        * which is necessary for PER domain transition. If the drivers
+        * are not compiled into the kernel HWMOD code will not change the
+        * state of the IPs if the IP was not never enabled
+        */
+       for (i = 0; i < ARRAY_SIZE(am33xx_mod); i++)
+               am33xx_mod[i].dev = omap_device_get_by_hwmod_name(am33xx_mod[i].oh_name);
+
+       gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
+       per_pwrdm = pwrdm_lookup("per_pwrdm");
+       mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+
+       gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
+
+       if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm) || (!gfx_l4ls_clkdm)) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       am33xx_pm = kzalloc(sizeof(*am33xx_pm), GFP_KERNEL);
+       if (!am33xx_pm) {
+               pr_err("Memory allocation failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = am33xx_map_emif();
+       if (ret) {
+               pr_err("PM: Could not ioremap EMIF\n");
+               goto err;
+       }
+       /* Determine Memory Type */
+       temp = readl(am33xx_emif_base + EMIF_SDRAM_CONFIG);
+       temp = (temp & SDRAM_TYPE_MASK) >> SDRAM_TYPE_SHIFT;
+       /* Parameters to pass to aseembly code */
+       susp_params.emif_addr_virt = am33xx_emif_base;
+       susp_params.dram_sync = am33xx_dram_sync;
+       susp_params.mem_type = temp;
+       am33xx_pm->ipc.param3 = temp;
+
+       np = of_find_compatible_node(NULL, NULL, "ti,am3353-wkup-m3");
+       if (np) {
+               if (of_find_property(np, "ti,needs_vtt_toggle", NULL) &&
+                   (!(of_property_read_u32(np, "vtt-gpio-pin",
+                                                       &temp)))) {
+                       if (temp >= 0 && temp <= 31)
+                               am33xx_pm->ipc.param3 |=
+                                       ((1 << VTT_STAT_SHIFT) |
+                                       (temp << VTT_GPIO_PIN_SHIFT));
+               }
+       }
+
+       (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
+
+       /* CEFUSE domain can be turned off post bootup */
+       cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
+       if (cefuse_pwrdm)
+               omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
+       else
+               pr_err("PM: Failed to get cefuse_pwrdm\n");
+
+#ifdef CONFIG_SUSPEND
+       pr_info("PM: Trying to load am335x-pm-firmware.bin");
+
+       /* We don't want to delay boot */
+       request_firmware_nowait(THIS_MODULE, 0, "am335x-pm-firmware.bin",
+                               NULL, GFP_KERNEL, am33xx_pm,
+                               am33xx_pm_firmware_cb);
+#endif /* CONFIG_SUSPEND */
+
+err:
+       return ret;
+}
arch/arm/mach-omap2/pm33xx.h new file +77 -0
new file mode 100644
index 0000000..befdd11
@@ -0,0 +1,77 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_PM33XX_H
+#define __ARCH_ARM_MACH_OMAP2_PM33XX_H
+
+#include "control.h"
+
+#ifndef __ASSEMBLER__
+
+struct am33xx_pm_context {
+       struct am33xx_ipc_data  ipc;
+       struct firmware         *firmware;
+       struct omap_mbox        *mbox;
+       u8                      state;
+       u32                     ver;
+};
+
+/*
+ * Params passed to suspend routine
+ *
+ * Since these are used to load into registers by suspend code,
+ * entries here must always be in sync with the suspend code
+ * in arm/mach-omap2/sleep33xx.S
+ */
+struct am33xx_suspend_params {
+       void __iomem *emif_addr_virt;
+       u32 mem_type;
+       void __iomem *dram_sync;
+};
+
+struct wakeup_src {
+       int irq_nr;
+       char src[10];
+};
+
+struct forced_standby_module {
+       char oh_name[15];
+       struct device *dev;
+};
+
+int wkup_m3_copy_code(const u8 *data, size_t size);
+int wkup_m3_prepare(void);
+void wkup_m3_register_txev_handler(void (*txev_handler)(void));
+
+#endif
+
+#define        IPC_CMD_DS0                     0x3
+#define IPC_CMD_RESET                   0xe
+#define DS_IPC_DEFAULT                 0xffffffff
+#define M3_VERSION_UNKNOWN             0x0000ffff
+#define M3_BASELINE_VERSION            0x21
+
+#define M3_STATE_UNKNOWN               0
+#define M3_STATE_RESET                 1
+#define M3_STATE_INITED                        2
+#define M3_STATE_MSG_FOR_LP            3
+#define M3_STATE_MSG_FOR_RESET         4
+
+#define AM33XX_OCMC_END                        0x40310000
+#define AM33XX_EMIF_BASE               0x4C000000
+
+#define MEM_TYPE_DDR2          2
+
+#endif
arch/arm/mach-omap2/wkup_m3.c new file +88 -0
new file mode 100644
index 0000000..8eaa7f3
@@ -0,0 +1,183 @@
+/*
+ * AM33XX Power Management Routines
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Vaibhav Bedia <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+
+#include "pm33xx.h"
+#include "control.h"
+#include "omap_device.h"
+#include "soc.h"
+
+struct wkup_m3_context {
+       struct device   *dev;
+       void __iomem    *code;
+       void (*txev_handler)(void);
+};
+
+struct wkup_m3_context *wkup_m3;
+
+int wkup_m3_copy_code(const u8 *data, size_t size)
+{
+       if (size > SZ_16K)
+               return -ENOMEM;
+
+       memcpy_toio(wkup_m3->code, data, size);
+
+       return 0;
+}
+
+
+void wkup_m3_register_txev_handler(void (*txev_handler)(void))
+{
+       wkup_m3->txev_handler = txev_handler;
+}
+
+/* have platforms do what they want in atomic context over here? */
+static irqreturn_t wkup_m3_txev_handler(int irq, void *unused)
+{
+       am33xx_txev_eoi();
+
+       /* callback to be executed in atomic context */
+       /* return 0 implies IRQ_HANDLED else IRQ_NONE */
+       wkup_m3->txev_handler();
+
+       am33xx_txev_enable();
+
+       return IRQ_HANDLED;
+}
+
+int wkup_m3_prepare(void)
+{
+       struct platform_device *pdev = to_platform_device(wkup_m3->dev);
+
+       /* check that the code is loaded */
+       omap_device_deassert_hardreset(pdev, "wkup_m3");
+
+       return 0;
+}
+
+static int wkup_m3_probe(struct platform_device *pdev)
+{
+       int irq, ret = 0;
+       struct resource *mem;
+
+       pm_runtime_enable(&pdev->dev);

arch/arm/mach-omap2/wkup_m3.c line 98

Quoted 10 lines
arch/arm/mach-omap2/wkup_m3.c new file +10 -0
+
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+               return ret;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq) {
+               dev_err(wkup_m3->dev, "no irq resource\n");

&pdev->dev

arch/arm/mach-omap2/wkup_m3.c line 105

Quoted 7 lines
arch/arm/mach-omap2/wkup_m3.c new file +7 -0
+               ret = -ENXIO;
+               goto err;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(wkup_m3->dev, "no memory resource\n");

&pdev->dev

Quoted 85 lines
arch/arm/mach-omap2/wkup_m3.c new file +78 -1
+               ret = -ENXIO;
+               goto err;
+       }
+
+       wkup_m3 = kzalloc(sizeof(*wkup_m3), GFP_KERNEL);
+       if (!wkup_m3) {
+               pr_err("Memory allocation failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       wkup_m3->dev = &pdev->dev;
+
+       wkup_m3->code = devm_request_and_ioremap(wkup_m3->dev, mem);
+       if (!wkup_m3->code) {
+               dev_err(wkup_m3->dev, "could not ioremap\n");
+               ret = -EADDRNOTAVAIL;
+               goto err;
+       }
+
+       ret = devm_request_irq(wkup_m3->dev, irq, wkup_m3_txev_handler,
+                 IRQF_DISABLED, "wkup_m3_txev", NULL);
+       if (ret) {
+               dev_err(wkup_m3->dev, "request_irq failed\n");
+               goto err;
+       }
+
+err:
+       return ret;
+}
+
+static int wkup_m3_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct of_device_id wkup_m3_dt_ids[] = {
+       { .compatible = "ti,am3353-wkup-m3" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wkup_m3_dt_ids);
+
+static int wkup_m3_rpm_suspend(struct device *dev)
+{
+       return -EBUSY;
+}
+
+static int wkup_m3_rpm_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops wkup_m3_ops = {
+       SET_RUNTIME_PM_OPS(wkup_m3_rpm_suspend, wkup_m3_rpm_resume, NULL)
+};
+
+static struct platform_driver wkup_m3_driver = {
+       .probe          = wkup_m3_probe,
+       .remove         = wkup_m3_remove,
+       .driver         = {
+               .name   = "wkup_m3",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(wkup_m3_dt_ids),
+               .pm     = &wkup_m3_ops,
+       },
+};
+
+static __init int wkup_m3_init(void)
+{
+       return platform_driver_register(&wkup_m3_driver);
+}
+
+static __exit void wkup_m3_exit(void)
+{
+       platform_driver_unregister(&wkup_m3_driver);
+}
+omap_postcore_initcall(wkup_m3_init);
+module_exit(wkup_m3_exit);
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#78 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 1 line · Russ Dill

On Tue, Aug 6, 2013 at 10:49 AM, Dave Gerlach <[email protected]> wrote:

[...]

Quoted 27 lines
Quoted 6 lines
arch/arm/mach-omap2/wkup_m3.c new file +6 -0
+static int wkup_m3_probe(struct platform_device *pdev)
+{
+       int irq, ret = 0;
+       struct resource *mem;
+
+       pm_runtime_enable(&pdev->dev);

arch/arm/mach-omap2/wkup_m3.c line 98

Quoted 10 lines
arch/arm/mach-omap2/wkup_m3.c new file +10 -0
+
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+               return ret;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq) {
+               dev_err(wkup_m3->dev, "no irq resource\n");

&pdev->dev

arch/arm/mach-omap2/wkup_m3.c line 105

Quoted 7 lines
arch/arm/mach-omap2/wkup_m3.c new file +7 -0
+               ret = -ENXIO;
+               goto err;
+       }
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(wkup_m3->dev, "no memory resource\n");
Quoted 1 line

&pdev->dev

For future reference, when reviewing, please trim to only relevant content/context, especially on large patches so maintainers/reviewers do not have to find 2 one-line comments in a huge amount of irrelevant context.

Thanks,

Kevin

#79 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Dave Gerlach
Quoted 21 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

AM335x supports various low power modes as documented in section 8.1.4.3 of the AM335x TRM which is available @ http://www.ti.com/litv/pdf/spruh73f

DeepSleep0 mode offers the lowest power mode with limited wakeup sources without a system reboot and is mapped as the suspend state in the kernel. In this state, MPU and PER domains are turned off with the internal RAM held in retention to facilitate resume process. As part of the boot process, the assembly code is copied over to OCMCRAM using the OMAP SRAM code.

AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU in DeepSleep0 entry and exit. WKUP_M3 takes care of the clockdomain and powerdomain transitions based on the intended low power state. MPU needs to load the appropriate WKUP_M3 binary onto the WKUP_M3 memory space before it can leverage any of the PM features like DeepSleep.

Quoted 5 lines

The IPC mechanism between MPU and WKUP_M3 uses a mailbox sub-module and 8 IPC registers in the Control module. MPU uses the assigned Mailbox for issuing an interrupt to WKUP_M3 which then goes and checks the IPC registers for the payload. WKUP_M3 has the ability to trigger on interrupt

s/trigger on interrupt/trigger an interrupt/ ??

Quoted 28 lines

to MPU by executing the "sev" instruction.

In the current implementation when the suspend process is initiated MPU interrupts the WKUP_M3 to let it know about the intent of entering DeepSleep0 and waits for an ACK. When the ACK is received MPU continues with its suspend process to suspend all the drivers and then jumps to assembly in OCMC RAM. The assembly code puts the PLLs in bypass, puts the external RAM in self-refresh mode and then finally execute the WFI instruction. Execution of the WFI instruction triggers another interrupt to the WKUP_M3 which then continues wiht the power down sequence wherein the clockdomain and powerdomain transition takes place. As part of the sleep sequence, WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI execution on WKUP_M3 causes the hardware to disable the main oscillator of the SoC.

When a wakeup event occurs, WKUP_M3 starts the power-up sequence by switching on the power domains and finally enabling the clock to MPU. Since the MPU gets powered down as part of the sleep sequence in the resume path ROM code starts executing. The ROM code detects a wakeup from sleep and then jumps to the resume location in OCMC which was populated in one of the IPC registers as part of the suspend sequence.

The low level code in OCMC relocks the PLLs, enables access to external RAM and then jumps to the cpu_resume code of the kernel to finish the resume process.

[...]

Quoted 3 lines
 arch/arm/mach-omap2/pm33xx.c  |  474 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h  |   77 +++++++
 arch/arm/mach-omap2/wkup_m3.c |  183 ++++++++++++++++

Looking closer at this code as I'm trying to fully get my head around all the IPC, I have some more comments.

I think the split between pm33xx.c and the M3 driver is still confusing here. For example, am33xx_ping_wkup_m3(), am33xx_m3_state_machine_reset() and the guts of am33xx_pm_begin() all belong inside the M3 driver, along with all the wakeup_src stuff, which is info coming from the M3.

IOW, the communication with M3 should be abstracted from pm33xx by the M3 driver (or possibly an eventual remoteproc/rpmsg implementation) with a well defined API. In this implementation, the interface is pretty fuzzy and mixed between pm33xx.c and wkup_m3.c.

Kevin

P.S. I'd also suggest renaming wakeup_src to something else since it's close to wakeup_source which has a rather different meaning in the kernel (c.f. linux/pm_wakeup.h)

#80 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 23 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

AM335x supports various low power modes as documented in section 8.1.4.3 of the AM335x TRM which is available @ http://www.ti.com/litv/pdf/spruh73f

DeepSleep0 mode offers the lowest power mode with limited wakeup sources without a system reboot and is mapped as the suspend state in the kernel. In this state, MPU and PER domains are turned off with the internal RAM held in retention to facilitate resume process. As part of the boot process, the assembly code is copied over to OCMCRAM using the OMAP SRAM code.

AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU in DeepSleep0 entry and exit. WKUP_M3 takes care of the clockdomain and powerdomain transitions based on the intended low power state. MPU needs to load the appropriate WKUP_M3 binary onto the WKUP_M3 memory space before it can leverage any of the PM features like DeepSleep.

Quoted 7 lines
Quoted 5 lines

The IPC mechanism between MPU and WKUP_M3 uses a mailbox sub-module and 8 IPC registers in the Control module. MPU uses the assigned Mailbox for issuing an interrupt to WKUP_M3 which then goes and checks the IPC registers for the payload. WKUP_M3 has the ability to trigger on interrupt

s/trigger on interrupt/trigger an interrupt/ ??

Oops I will fix that.

Quoted 46 lines
Quoted 29 lines

to MPU by executing the "sev" instruction.

In the current implementation when the suspend process is initiated MPU interrupts the WKUP_M3 to let it know about the intent of entering DeepSleep0 and waits for an ACK. When the ACK is received MPU continues with its suspend process to suspend all the drivers and then jumps to assembly in OCMC RAM. The assembly code puts the PLLs in bypass, puts the external RAM in self-refresh mode and then finally execute the WFI instruction. Execution of the WFI instruction triggers another interrupt to the WKUP_M3 which then continues wiht the power down sequence wherein the clockdomain and powerdomain transition takes place. As part of the sleep sequence, WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI execution on WKUP_M3 causes the hardware to disable the main oscillator of the SoC.

When a wakeup event occurs, WKUP_M3 starts the power-up sequence by switching on the power domains and finally enabling the clock to MPU. Since the MPU gets powered down as part of the sleep sequence in the resume path ROM code starts executing. The ROM code detects a wakeup from sleep and then jumps to the resume location in OCMC which was populated in one of the IPC registers as part of the suspend sequence.

The low level code in OCMC relocks the PLLs, enables access to external RAM and then jumps to the cpu_resume code of the kernel to finish the resume process.

[...]

Quoted 3 lines
  arch/arm/mach-omap2/pm33xx.c  |  474 +++++++++++++++++++++++++++++++++++++++++
  arch/arm/mach-omap2/pm33xx.h  |   77 +++++++
  arch/arm/mach-omap2/wkup_m3.c |  183 ++++++++++++++++

Looking closer at this code as I'm trying to fully get my head around all the IPC, I have some more comments.

I think the split between pm33xx.c and the M3 driver is still confusing here. For example, am33xx_ping_wkup_m3(), am33xx_m3_state_machine_reset() and the guts of am33xx_pm_begin() all belong inside the M3 driver, along with all the wakeup_src stuff, which is info coming from the M3.

Quoted 4 lines

IOW, the communication with M3 should be abstracted from pm33xx by the M3 driver (or possibly an eventual remoteproc/rpmsg implementation) with a well defined API. In this implementation, the interface is pretty fuzzy and mixed between pm33xx.c and wkup_m3.c.

I have since moved much more of the m3 functionality, including the ping and wakeup src code, into the wkup_m3 driver to make the split more clear but I haven't yet moved the state machine portion into the wkup_m3 driver. I feel that this is the portion of the IPC that could potentially be the most variant between different SoC implementations so leaving this in the pm code should allow for more flexibility.

Quoted 7 lines

Kevin

P.S. I'd also suggest renaming wakeup_src to something else since it's close to wakeup_source which has a rather different meaning in the kernel (c.f. linux/pm_wakeup.h)

I will rename this to tie it into the M3 code.

Regards,
Dave

#81 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 85 lines · Dave Gerlach
Quoted 23 lines · Kevin Hilman
Quoted 21 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

AM335x supports various low power modes as documented in section 8.1.4.3 of the AM335x TRM which is available @ http://www.ti.com/litv/pdf/spruh73f

DeepSleep0 mode offers the lowest power mode with limited wakeup sources without a system reboot and is mapped as the suspend state in the kernel. In this state, MPU and PER domains are turned off with the internal RAM held in retention to facilitate resume process. As part of the boot process, the assembly code is copied over to OCMCRAM using the OMAP SRAM code.

AM335x has a Cortex-M3 (WKUP_M3) which assists the MPU in DeepSleep0 entry and exit. WKUP_M3 takes care of the clockdomain and powerdomain transitions based on the intended low power state. MPU needs to load the appropriate WKUP_M3 binary onto the WKUP_M3 memory space before it can leverage any of the PM features like DeepSleep.

Quoted 7 lines
Quoted 5 lines

The IPC mechanism between MPU and WKUP_M3 uses a mailbox sub-module and 8 IPC registers in the Control module. MPU uses the assigned Mailbox for issuing an interrupt to WKUP_M3 which then goes and checks the IPC registers for the payload. WKUP_M3 has the ability to trigger on interrupt

s/trigger on interrupt/trigger an interrupt/ ??

Oops I will fix that.

Quoted 46 lines
Quoted 29 lines

to MPU by executing the "sev" instruction.

In the current implementation when the suspend process is initiated MPU interrupts the WKUP_M3 to let it know about the intent of entering DeepSleep0 and waits for an ACK. When the ACK is received MPU continues with its suspend process to suspend all the drivers and then jumps to assembly in OCMC RAM. The assembly code puts the PLLs in bypass, puts the external RAM in self-refresh mode and then finally execute the WFI instruction. Execution of the WFI instruction triggers another interrupt to the WKUP_M3 which then continues wiht the power down sequence wherein the clockdomain and powerdomain transition takes place. As part of the sleep sequence, WKUP_M3 unmasks the interrupt lines for the wakeup sources. WFI execution on WKUP_M3 causes the hardware to disable the main oscillator of the SoC.

When a wakeup event occurs, WKUP_M3 starts the power-up sequence by switching on the power domains and finally enabling the clock to MPU. Since the MPU gets powered down as part of the sleep sequence in the resume path ROM code starts executing. The ROM code detects a wakeup from sleep and then jumps to the resume location in OCMC which was populated in one of the IPC registers as part of the suspend sequence.

The low level code in OCMC relocks the PLLs, enables access to external RAM and then jumps to the cpu_resume code of the kernel to finish the resume process.

[...]

Quoted 3 lines
  arch/arm/mach-omap2/pm33xx.c  |  474 +++++++++++++++++++++++++++++++++++++++++
  arch/arm/mach-omap2/pm33xx.h  |   77 +++++++
  arch/arm/mach-omap2/wkup_m3.c |  183 ++++++++++++++++

Looking closer at this code as I'm trying to fully get my head around all the IPC, I have some more comments.

I think the split between pm33xx.c and the M3 driver is still confusing here. For example, am33xx_ping_wkup_m3(), am33xx_m3_state_machine_reset() and the guts of am33xx_pm_begin() all belong inside the M3 driver, along with all the wakeup_src stuff, which is info coming from the M3.

Quoted 4 lines

IOW, the communication with M3 should be abstracted from pm33xx by the M3 driver (or possibly an eventual remoteproc/rpmsg implementation) with a well defined API. In this implementation, the interface is pretty fuzzy and mixed between pm33xx.c and wkup_m3.c.

Quoted 6 lines

I have since moved much more of the m3 functionality, including the ping and wakeup src code, into the wkup_m3 driver to make the split more clear but I haven't yet moved the state machine portion into the wkup_m3 driver. I feel that this is the portion of the IPC that could potentially be the most variant between different SoC implementations so leaving this in the pm code should allow for more flexibility.

I still think this belogs in the M3 driver, because AFAICT, it's specific to the M3 firmware, not to the SoC.

Quoted 9 lines
Quoted 7 lines

Kevin

P.S. I'd also suggest renaming wakeup_src to something else since it's close to wakeup_source which has a rather different meaning in the kernel (c.f. linux/pm_wakeup.h)

I will rename this to tie it into the M3 code.

Great, thanks.

Kevin

#82 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

In reply to Kevin Hilman

On Tue, Aug 27, 2013 at 5:45 PM, Kevin Hilman <[email protected]> wrote:
[...]

Quoted 10 lines

Looking closer at this code as I'm trying to fully get my head around all the IPC, I have some more comments.

I think the split between pm33xx.c and the M3 driver is still confusing here. For example, am33xx_ping_wkup_m3(), am33xx_m3_state_machine_reset() and the guts of am33xx_pm_begin() all belong inside the M3 driver, along with all the wakeup_src stuff, which is info coming from the M3.

Quoted 6 lines

IOW, the communication with M3 should be abstracted from pm33xx by the M3 driver (or possibly an eventual remoteproc/rpmsg implementation) with a well defined API. In this implementation, the interface is pretty fuzzy and mixed between pm33xx.c and wkup_m3.c.

The reason for the current split was to have the M3 driver just do the minimal that's needed to talk to get M3 and MPU talking. What made me do it this way was to attempt to address a previous comment on keeping options open for folks to use M3 for things other than PM stuff. The IPC stuff is how implementors of the
firmware (anything other than the PM one that TI provides) want it to be.

The top level idea was to have the users of the firmware (PM in this case) decide what functionality they want when talking to M3. They are also free to decide the register bitfield layout and other IPC details.

This was also a feeble attempt to keep things extensible for AM437x where in addition to the broken mailbox usage there's now a control module bit to trigger the interrupt to M3 (what's worse? pick one that you hate more ;) The AM437x PM routines could then just register different callbacks that are triggered when the M3 interrupts the MPU.

Hope this clears up some of the confusion.

Regards,
Vaibhav

#83 lore raw

PATCH v3 8/9 ARM: OMAP2+: AM33XX: Basic suspend resume support

Quoted 19 lines · Vaibhav Bedia

On Tue, Aug 27, 2013 at 5:45 PM, Kevin Hilman <[email protected]> wrote:
[...]

Quoted 10 lines

Looking closer at this code as I'm trying to fully get my head around all the IPC, I have some more comments.

I think the split between pm33xx.c and the M3 driver is still confusing here. For example, am33xx_ping_wkup_m3(), am33xx_m3_state_machine_reset() and the guts of am33xx_pm_begin() all belong inside the M3 driver, along with all the wakeup_src stuff, which is info coming from the M3.

Quoted 6 lines

IOW, the communication with M3 should be abstracted from pm33xx by the M3 driver (or possibly an eventual remoteproc/rpmsg implementation) with a well defined API. In this implementation, the interface is pretty fuzzy and mixed between pm33xx.c and wkup_m3.c.

Quoted 6 lines

The reason for the current split was to have the M3 driver just do the minimal that's needed to talk to get M3 and MPU talking. What made me do it this way was to attempt to address a previous comment on keeping options open for folks to use M3 for things other than PM stuff. The IPC stuff is how implementors of the
firmware (anything other than the PM one that TI provides) want it to be.

IMO, there should actually be 3 levels. the SoC PM implementation (pm33xx.c), the M3 driver where the protocol, state-machine, etc. are handled, and the messaging layer. In the current proposal, the last 2 are combined, but I'd really like to see a generalized messaging layer that everyone else using an M3 coprocessor might use as well. As mentioned already, I think that should be rpmsg, but that still needs some exploration.

Quoted 7 lines

The top level idea was to have the users of the firmware (PM in this case) decide what functionality they want when talking to M3. They are also free to decide the register bitfield layout and other IPC details.

This was also a feeble attempt to keep things extensible for AM437x where in addition to the broken mailbox usage there's now a control module bit to trigger the interrupt to M3 (what's worse? pick one that you hate more ;)

Sounds like AM43xx is better. If you have a control module bit to trigger an interrupt, why do you need the mailbox at all?

Quoted 4 lines

The AM437x PM routines could then just register different callbacks that are triggered when the M3 interrupts the MPU.

Hope this clears up some of the confusion.

Thanks,

Kevin

#84 lore raw

PATCH v3 9/9 ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP builds

In reply to Dave Gerlach

From: Vaibhav Bedia <[email protected]>

With all the requisite changes in place we can now enable the basic PM support for AM335x. This patch updates the various OMAP files to enable suspend-resume on AM335x.

---
 arch/arm/mach-omap2/Kconfig         |    7 +++++--
 arch/arm/mach-omap2/Makefile        |    2 ++
 arch/arm/mach-omap2/board-generic.c |    1 +
 arch/arm/mach-omap2/common.h        |   10 ++++++++++
 arch/arm/mach-omap2/io.c            |    5 +++++
 arch/arm/mach-omap2/pm.c            |    3 ++-
 arch/arm/mach-omap2/pm.h            |    5 +++++
 arch/arm/mach-omap2/sram.c          |   10 +++++++++-
 arch/arm/mach-omap2/sram.h          |    2 ++
 9 files changed, 41 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/Kconfig +5 -2
index 3eed000..ef3fe40 100644
@@ -67,11 +67,14 @@ config SOC_OMAP5
 config SOC_AM33XX
 	bool "AM33XX support"
 	depends on ARCH_MULTI_V7
-	select ARCH_OMAP2PLUS
+	default y
 	select ARM_CPU_SUSPEND if PM
+	select COMMON_CLK
 	select CPU_V7
+	select MAILBOX if PM
 	select MULTI_IRQ_HANDLER
-	select COMMON_CLK
+	select OMAP_MBOX_FWK if PM
+	select OMAP2PLUS_MBOX if PM
 
 config SOC_AM43XX
 	bool "TI AM43x"
arch/arm/mach-omap2/Makefile +2 -0
index d4f6715..eb3a47a 100644
@@ -87,6 +87,7 @@ obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o
 obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
 obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o omap-mpuss-lowpower.o
 obj-$(CONFIG_SOC_OMAP5)			+= omap-mpuss-lowpower.o
+obj-$(CONFIG_SOC_AM33XX)		+= pm33xx.o sleep33xx.o wkup_m3.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 
 obj-$(CONFIG_POWER_AVS_OMAP)		+= sr_device.o
@@ -94,6 +95,7 @@ obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a$(plus_sec)
+AFLAGS_sleep33xx.o			:=-Wa,-march=armv7-a$(plus_sec)
 
 endif
 
arch/arm/mach-omap2/board-generic.c +1 -0
index aed750c..3f2d6a7 100644
@@ -159,6 +159,7 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
 	.reserve	= am33xx_reserve,
 	.map_io		= am33xx_map_io,
 	.init_early	= am33xx_init_early,
+	.init_late	= am33xx_init_late,
 	.init_irq	= omap_intc_of_init,
 	.handle_irq	= omap3_intc_handle_irq,
 	.init_machine	= omap_generic_init,
arch/arm/mach-omap2/common.h +10 -0
index 6b8ef74..80bf0da 100644
@@ -69,6 +69,15 @@ static inline int omap4_pm_init(void)
 }
 #endif
 
+#if defined(CONFIG_PM) && defined(CONFIG_SOC_AM33XX)
+int am33xx_pm_init(void);
+#else
+static inline int am33xx_pm_init(void)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_OMAP_MUX
 int omap_mux_late_init(void);
 #else
@@ -107,6 +116,7 @@ void omap2430_init_late(void);
 void omap3430_init_late(void);
 void omap35xx_init_late(void);
 void omap3630_init_late(void);
+void am33xx_init_late(void);
 void am35xx_init_late(void);
 void ti81xx_init_late(void);
 int omap2_common_pm_late_init(void);
arch/arm/mach-omap2/io.c +5 -0
index 3ad7543..63516e5 100644
@@ -584,6 +584,11 @@ void __init am33xx_init_early(void)
 	omap_hwmod_init_postsetup();
 	omap_clk_init = am33xx_clk_init;
 }
+
+void __init am33xx_init_late(void)
+{
+	am33xx_pm_init();
+}
 #endif
 
 #ifdef CONFIG_SOC_AM43XX
arch/arm/mach-omap2/pm.c +2 -1
index e742118..f8bd883 100644
@@ -305,7 +305,8 @@ int __init omap2_common_pm_late_init(void)
 	}
 
 #ifdef CONFIG_SUSPEND
-	suspend_set_ops(&omap_pm_ops);
+	if (!soc_is_am33xx())
+		suspend_set_ops(&omap_pm_ops);
 #endif
 
 	return 0;
arch/arm/mach-omap2/pm.h +5 -0
index 7bdd22a..5122bb6 100644
@@ -82,6 +82,11 @@ extern unsigned int omap3_do_wfi_sz;
 /* ... and its pointer from SRAM after copy */
 extern void (*omap3_do_wfi_sram)(void);
 
+/* am33xx_do_wfi function pointer and size, for copy to SRAM */
+extern void am33xx_do_wfi(void);
+extern unsigned int am33xx_do_wfi_sz;
+extern unsigned int am33xx_resume_offset;
+
 /* save_secure_ram_context function pointer and size, for copy to SRAM */
 extern int save_secure_ram_context(u32 *addr);
 extern unsigned int save_secure_ram_context_sz;
arch/arm/mach-omap2/sram.c +9 -1
index 4bd0968..303c562 100644
@@ -154,7 +154,7 @@ static void __init omap2_map_sram(void)
 		omap_sram_size -= SZ_16K;
 	}
 #endif
-	if (cpu_is_omap34xx()) {
+	if (cpu_is_omap34xx() || soc_is_am33xx()) {
 		/*
 		 * SRAM must be marked as non-cached on OMAP3 since the
 		 * CORE DPLL M2 divider change code (in SRAM) runs with the
@@ -285,10 +285,18 @@ static inline int omap34xx_sram_init(void)
 }
 #endif /* CONFIG_ARCH_OMAP3 */
 
+#ifdef CONFIG_SOC_AM33XX
 static inline int am33xx_sram_init(void)
 {
+	am33xx_push_sram_idle();
 	return 0;
 }
+#else
+static inline int am33xx_sram_init(void)
+{
+	return 0;
+}
+#endif
 
 int __init omap_sram_init(void)
 {
arch/arm/mach-omap2/sram.h +2 -0
index ca7277c..24788b5 100644
@@ -62,8 +62,10 @@ extern unsigned long omap3_sram_configure_core_dpll_sz;
 
 #ifdef CONFIG_PM
 extern void omap_push_sram_idle(void);
+extern void am33xx_push_sram_idle(void);
 #else
 static inline void omap_push_sram_idle(void) {}
+static inline void am33xx_push_sram_idle(void) {}
 #endif /* CONFIG_PM */
 
 #endif /* __ASSEMBLY__ */
Signature · 1 line
1.7.9.5
#85 lore raw

PATCH v3 9/9 ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP builds

Quoted 9 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

With all the requisite changes in place we can now enable the basic PM support for AM335x. This patch updates the various OMAP files to enable suspend-resume on AM335x.

Quoted 193 lines
---
 arch/arm/mach-omap2/Kconfig         |    7 +++++--
 arch/arm/mach-omap2/Makefile        |    2 ++
 arch/arm/mach-omap2/board-generic.c |    1 +
 arch/arm/mach-omap2/common.h        |   10 ++++++++++
 arch/arm/mach-omap2/io.c            |    5 +++++
 arch/arm/mach-omap2/pm.c            |    3 ++-
 arch/arm/mach-omap2/pm.h            |    5 +++++
 arch/arm/mach-omap2/sram.c          |   10 +++++++++-
 arch/arm/mach-omap2/sram.h          |    2 ++
 9 files changed, 41 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/Kconfig +5 -2
index 3eed000..ef3fe40 100644
@@ -67,11 +67,14 @@ config SOC_OMAP5
 config SOC_AM33XX
        bool "AM33XX support"
        depends on ARCH_MULTI_V7
-       select ARCH_OMAP2PLUS
+       default y
        select ARM_CPU_SUSPEND if PM
+       select COMMON_CLK
        select CPU_V7
+       select MAILBOX if PM
        select MULTI_IRQ_HANDLER
-       select COMMON_CLK
+       select OMAP_MBOX_FWK if PM
+       select OMAP2PLUS_MBOX if PM
 
 config SOC_AM43XX
        bool "TI AM43x"
arch/arm/mach-omap2/Makefile +2 -0
index d4f6715..eb3a47a 100644
@@ -87,6 +87,7 @@ obj-$(CONFIG_ARCH_OMAP2)              += sleep24xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o
 obj-$(CONFIG_ARCH_OMAP4)               += pm44xx.o omap-mpuss-lowpower.o
 obj-$(CONFIG_SOC_OMAP5)                        += omap-mpuss-lowpower.o
+obj-$(CONFIG_SOC_AM33XX)               += pm33xx.o sleep33xx.o wkup_m3.o
 obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
 
 obj-$(CONFIG_POWER_AVS_OMAP)           += sr_device.o
@@ -94,6 +95,7 @@ obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
 
 AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
 AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
+AFLAGS_sleep33xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
 
 endif
 
arch/arm/mach-omap2/board-generic.c +1 -0
index aed750c..3f2d6a7 100644
@@ -159,6 +159,7 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
        .reserve        = am33xx_reserve,
        .map_io         = am33xx_map_io,
        .init_early     = am33xx_init_early,
+       .init_late      = am33xx_init_late,
        .init_irq       = omap_intc_of_init,
        .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_generic_init,
arch/arm/mach-omap2/common.h +10 -0
index 6b8ef74..80bf0da 100644
@@ -69,6 +69,15 @@ static inline int omap4_pm_init(void)
 }
 #endif
 
+#if defined(CONFIG_PM) && defined(CONFIG_SOC_AM33XX)
+int am33xx_pm_init(void);
+#else
+static inline int am33xx_pm_init(void)
+{
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_OMAP_MUX
 int omap_mux_late_init(void);
 #else
@@ -107,6 +116,7 @@ void omap2430_init_late(void);
 void omap3430_init_late(void);
 void omap35xx_init_late(void);
 void omap3630_init_late(void);
+void am33xx_init_late(void);
 void am35xx_init_late(void);
 void ti81xx_init_late(void);
 int omap2_common_pm_late_init(void);
arch/arm/mach-omap2/io.c +5 -0
index 3ad7543..63516e5 100644
@@ -584,6 +584,11 @@ void __init am33xx_init_early(void)
        omap_hwmod_init_postsetup();
        omap_clk_init = am33xx_clk_init;
 }
+
+void __init am33xx_init_late(void)
+{
+       am33xx_pm_init();
+}
 #endif
 
 #ifdef CONFIG_SOC_AM43XX
arch/arm/mach-omap2/pm.c +2 -1
index e742118..f8bd883 100644
@@ -305,7 +305,8 @@ int __init omap2_common_pm_late_init(void)
        }
 
 #ifdef CONFIG_SUSPEND
-       suspend_set_ops(&omap_pm_ops);
+       if (!soc_is_am33xx())
+               suspend_set_ops(&omap_pm_ops);
 #endif
 
        return 0;
arch/arm/mach-omap2/pm.h +5 -0
index 7bdd22a..5122bb6 100644
@@ -82,6 +82,11 @@ extern unsigned int omap3_do_wfi_sz;
 /* ... and its pointer from SRAM after copy */
 extern void (*omap3_do_wfi_sram)(void);
 
+/* am33xx_do_wfi function pointer and size, for copy to SRAM */
+extern void am33xx_do_wfi(void);
+extern unsigned int am33xx_do_wfi_sz;
+extern unsigned int am33xx_resume_offset;
+
 /* save_secure_ram_context function pointer and size, for copy to SRAM */
 extern int save_secure_ram_context(u32 *addr);
 extern unsigned int save_secure_ram_context_sz;
arch/arm/mach-omap2/sram.c +9 -1
index 4bd0968..303c562 100644
@@ -154,7 +154,7 @@ static void __init omap2_map_sram(void)
                omap_sram_size -= SZ_16K;
        }
 #endif
-       if (cpu_is_omap34xx()) {
+       if (cpu_is_omap34xx() || soc_is_am33xx()) {
                /*
                 * SRAM must be marked as non-cached on OMAP3 since the
                 * CORE DPLL M2 divider change code (in SRAM) runs with the
@@ -285,10 +285,18 @@ static inline int omap34xx_sram_init(void)
 }
 #endif /* CONFIG_ARCH_OMAP3 */
 
+#ifdef CONFIG_SOC_AM33XX
 static inline int am33xx_sram_init(void)
 {
+       am33xx_push_sram_idle();
        return 0;
 }
+#else
+static inline int am33xx_sram_init(void)
+{
+       return 0;
+}
+#endif
 
 int __init omap_sram_init(void)
 {
arch/arm/mach-omap2/sram.h +2 -1
index ca7277c..24788b5 100644
@@ -62,8 +62,10 @@ extern unsigned long omap3_sram_configure_core_dpll_sz;
 
 #ifdef CONFIG_PM
 extern void omap_push_sram_idle(void);
+extern void am33xx_push_sram_idle(void);
 #else
 static inline void omap_push_sram_idle(void) {}
+static inline void am33xx_push_sram_idle(void) {}
 #endif /* CONFIG_PM */
 
 #endif /* __ASSEMBLY__ */
--

1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#86 lore raw

PATCH v3 9/9 ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP builds

In reply to Dave Gerlach
Quoted 9 lines · Dave Gerlach

From: Vaibhav Bedia <[email protected]>

With all the requisite changes in place we can now enable the basic PM support for AM335x. This patch updates the various OMAP files to enable suspend-resume on AM335x.

Quoted 12 lines
---
 arch/arm/mach-omap2/Kconfig         |    7 +++++--
 arch/arm/mach-omap2/Makefile        |    2 ++
 arch/arm/mach-omap2/board-generic.c |    1 +
 arch/arm/mach-omap2/common.h        |   10 ++++++++++
 arch/arm/mach-omap2/io.c            |    5 +++++
 arch/arm/mach-omap2/pm.c            |    3 ++-
 arch/arm/mach-omap2/pm.h            |    5 +++++
 arch/arm/mach-omap2/sram.c          |   10 +++++++++-
 arch/arm/mach-omap2/sram.h          |    2 ++
 9 files changed, 41 insertions(+), 4 deletions(-)

The patch looks fine but too many changes in one patch than my liking. No strong preference though.

#87 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

In reply to Dave Gerlach
Quoted 20 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

Quoted 8 lines

Changes in v3:
- Moved wkup_m3 code into separate driver
- Split up ti_emif header move
- Addressed clean-up comments
- Removed mailbox patches
- v2-v3 Discussion:
http://marc.info/?l=linux-arm-kernel&m=135698501821090&w=4

Please CC people who have at least reviewed the last version of the series. Couple of patches I was CC'ed o.w I would missed this series.

Regards,
Santosh

#88 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

In reply to Dave Gerlach

Hi Dave,

Thanks a lot for your work on this.

Quoted 5 lines · Dave Gerlach

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

I applied your set and the one from Suman Anna, and with musb disabled and the firmware built from the sources you referenced, I'm able to put a custom AM33xx based board to suspend.

The problem I currently face is that I can't make the board resume, as neither UART0 nor GPIO0 seem to work as wakeup source.

Which wakeup source did you use in your tests?

Thanks,
Daniel

#89 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 11 lines · Daniel Mack

Hi Dave,

Thanks a lot for your work on this.

Quoted 5 lines · Dave Gerlach

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

Quoted 6 lines

I applied your set and the one from Suman Anna, and with musb disabled and the firmware built from the sources you referenced, I'm able to put a custom AM33xx based board to suspend.

The problem I currently face is that I can't make the board resume, as neither UART0 nor GPIO0 seem to work as wakeup source.

Did you apply the other patches that are mentioned besides Suman's series? The board will hang while suspending without these.

Quoted 3 lines

Which wakeup source did you use in your tests?

Most of my verification was done with UART wakeup.

Quoted 4 lines

Thanks,
Daniel

#90 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Hi Dave,

Quoted 7 lines · Dave Gerlach
Quoted 2 lines · Daniel Mack

The problem I currently face is that I can't make the board resume, as neither UART0 nor GPIO0 seem to work as wakeup source.

Did you apply the other patches that are mentioned besides Suman's series? The board will hang while suspending without these.

Yes. However, just to make sure you referenced the correct patches - on top of yours an Suman's set, I have:

[PATCH 1/2] ARM: OMAP2+: hwmod: rt address space index for DT [PATCH 2/2] ARM: OMAP2+: hwmod: AM335x: fix cpgmac address space [PATCH 1/2] ARM: dts: add AM33XX EDMA support

The last one seems somewhat unrelated though.

However, I see an issue with the musb dsps glue. With the usb controller disabled in DT, I also had to remove the usb_otg_hs entry from am33xx_mod[] (pm33xx.c). When the usb controller is _enabled_, I get an instant NULL pointer exception due to a rather obvious bug. I'll send out a patch right now.

When I send the board to suspend (with USB disabled), the power consumption drops significantly, and the output is:

# echo mem > /sys/power/state
[   93.001937] PM: Syncing filesystems ... done.
[   93.033591] Freezing user space processes ... (elapsed 0.002 seconds)
done.
[   93.048532] Freezing remaining freezable tasks ... (elapsed 0.002
seconds) done.
[   93.059277] PM: Sending message for entering DeepSleep mode
[   93.085368] PM: suspend of devices complete after 15.070 msecs
[   93.096671] PM: late suspend of devices complete after 5.122 msecs
[   93.108853] PM: noirq suspend of devices complete after 5.647 msecs

... but traffic on UART0 won't cause a resume.

I'll dig a little deeper now, but if you have any idea, please let me know.

Thanks,
Daniel

#91 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 41 lines · Daniel Mack

Hi Dave,

Quoted 7 lines · Dave Gerlach
Quoted 2 lines · Daniel Mack

The problem I currently face is that I can't make the board resume, as neither UART0 nor GPIO0 seem to work as wakeup source.

Did you apply the other patches that are mentioned besides Suman's series? The board will hang while suspending without these.

Yes. However, just to make sure you referenced the correct patches - on top of yours an Suman's set, I have:

[PATCH 1/2] ARM: OMAP2+: hwmod: rt address space index for DT [PATCH 2/2] ARM: OMAP2+: hwmod: AM335x: fix cpgmac address space [PATCH 1/2] ARM: dts: add AM33XX EDMA support

The last one seems somewhat unrelated though.

However, I see an issue with the musb dsps glue. With the usb controller disabled in DT, I also had to remove the usb_otg_hs entry from am33xx_mod[] (pm33xx.c). When the usb controller is _enabled_, I get an instant NULL pointer exception due to a rather obvious bug. I'll send out a patch right now.

When I send the board to suspend (with USB disabled), the power consumption drops significantly, and the output is:

# echo mem > /sys/power/state
[   93.001937] PM: Syncing filesystems ... done.
[   93.033591] Freezing user space processes ... (elapsed 0.002 seconds)
done.
[   93.048532] Freezing remaining freezable tasks ... (elapsed 0.002
seconds) done.
[   93.059277] PM: Sending message for entering DeepSleep mode
[   93.085368] PM: suspend of devices complete after 15.070 msecs
[   93.096671] PM: late suspend of devices complete after 5.122 msecs
[   93.108853] PM: noirq suspend of devices complete after 5.647 msecs
Quoted 2 lines

... but traffic on UART0 won't cause a resume.

It looks like you are using no_console_suspend? UART0 does not work as a wakeup source with this option set.

Quoted 7 lines

I'll dig a little deeper now, but if you have any idea, please let me know.

Thanks,
Daniel

#92 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 7 lines · Dave Gerlach
Quoted 2 lines · Daniel Mack

... but traffic on UART0 won't cause a resume.

It looks like you are using no_console_suspend? UART0 does not work as a wakeup source with this option set.

Meh. Sorry, I didn't think about that possibility. Indeed, without that option, it does resume. Now I can search for the reason why other wakeup sources won't work yet, but that shouldn't bother you.

Thanks again,
Daniel

#93 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

In reply to Dave Gerlach
Quoted 15 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Quoted 4 lines

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

can you share the working repo which has all these patches applied?

Thanks & Regards
Gururaja

Quoted 67 lines

Changes in v3:
- Moved wkup_m3 code into separate driver
- Split up ti_emif header move
- Addressed clean-up comments
- Removed mailbox patches
- v2-v3 Discussion:
http://marc.info/?l=linux-arm-kernel&m=135698501821090&w=4

Changes in v2:
- Broke patches up to isolate assembly code and build hookup.
- Moved control module code to separate module
- v1->v2 Discussion:
http://lists.infradead.org/pipermail/linux-arm-kernel/2012-November/129508.html

Regards,
Dave

[1] http://marc.info/?l=linux-arm-kernel&m=137303736714638&w=4
[2] http://marc.info/?l=linux-omap&m=137303723114610&w=4
[3] http://marc.info/?l=linux-omap&m=137401384611934&w=4
[4] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=shortlog;h=refs/heads/next2

Dave Gerlach (1):
memory: emif: Move EMIF register defines to include/linux/

Vaibhav Bedia (8):
ARM: OMAP2+: AM33XX: control: Add some control module registers and
APIs
ARM: OMAP: DTB: Update IRQ data for WKUP_M3
ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec
ARM: OMAP2+: AM33XX: Add assembly code for PM operations
ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device
ARM: OMAP: omap_device: Add APIs to enable and idle hwmods
ARM: OMAP2+: AM33XX: Basic suspend resume support
ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP builds

 arch/arm/boot/dts/am33xx.dtsi       |    1 +
 arch/arm/mach-omap2/Kconfig         |    7 +-
 arch/arm/mach-omap2/Makefile        |    2 +
 arch/arm/mach-omap2/board-generic.c |    3 +-
 arch/arm/mach-omap2/common.c        |   28 ++
 arch/arm/mach-omap2/common.h        |   14 +
 arch/arm/mach-omap2/control.c       |   57 ++++
 arch/arm/mach-omap2/control.h       |   54 ++++
 arch/arm/mach-omap2/io.c            |    6 +
 arch/arm/mach-omap2/omap_device.c   |    8 +
 arch/arm/mach-omap2/omap_device.h   |    2 +
 arch/arm/mach-omap2/pm.c            |    3 +-
 arch/arm/mach-omap2/pm.h            |    5 +
 arch/arm/mach-omap2/pm33xx.c        |  474 +++++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm33xx.h        |   77 +++++
 arch/arm/mach-omap2/sleep33xx.S     |  350 ++++++++++++++++++++++
 arch/arm/mach-omap2/sram.c          |   10 +-
 arch/arm/mach-omap2/sram.h          |    2 +
 arch/arm/mach-omap2/timer.c         |   32 ++
 arch/arm/mach-omap2/wkup_m3.c       |  183 ++++++++++++
 drivers/memory/emif.h               |  543 +---------------------------------
 include/linux/ti_emif.h             |  558 +++++++++++++++++++++++++++++++++++
 22 files changed, 1872 insertions(+), 547 deletions(-)
 create mode 100644 arch/arm/mach-omap2/pm33xx.c
 create mode 100644 arch/arm/mach-omap2/pm33xx.h
 create mode 100644 arch/arm/mach-omap2/sleep33xx.S
 create mode 100644 arch/arm/mach-omap2/wkup_m3.c
 create mode 100644 include/linux/ti_emif.h
#94 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 18 lines · Gururaja Hebbar
Quoted 17 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Suspend to mem is tested on am335x-bone and am335x-evm.

Quoted 8 lines
Quoted 2 lines

More details on AM335x suspend-resume are provided within the commit logs for each patch.

can you share the working repo which has all these patches applied?

Thanks & Regards
Gururaja

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

Regards,
Dave

Quoted 68 lines
Quoted 67 lines

Changes in v3:
- Moved wkup_m3 code into separate driver
- Split up ti_emif header move
- Addressed clean-up comments
- Removed mailbox patches
- v2-v3 Discussion:
http://marc.info/?l=linux-arm-kernel&m=135698501821090&w=4

Changes in v2:
- Broke patches up to isolate assembly code and build hookup.
- Moved control module code to separate module
- v1->v2 Discussion:
http://lists.infradead.org/pipermail/linux-arm-kernel/2012-November/129508.html

Regards,
Dave

[1] http://marc.info/?l=linux-arm-kernel&m=137303736714638&w=4
[2] http://marc.info/?l=linux-omap&m=137303723114610&w=4
[3] http://marc.info/?l=linux-omap&m=137401384611934&w=4
[4] http://arago-project.org/git/projects/?p=am33x-cm3.git;a=shortlog;h=refs/heads/next2

Dave Gerlach (1):
memory: emif: Move EMIF register defines to include/linux/

Vaibhav Bedia (8):
ARM: OMAP2+: AM33XX: control: Add some control module registers and
APIs
ARM: OMAP: DTB: Update IRQ data for WKUP_M3
ARM: OMAP2+: AM33XX: Reserve memory to comply with EMIF spec
ARM: OMAP2+: AM33XX: Add assembly code for PM operations
ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device
ARM: OMAP: omap_device: Add APIs to enable and idle hwmods
ARM: OMAP2+: AM33XX: Basic suspend resume support
ARM: OMAP2+: AM33XX: Hookup AM33XX PM code into OMAP builds

  arch/arm/boot/dts/am33xx.dtsi       |    1 +
  arch/arm/mach-omap2/Kconfig         |    7 +-
  arch/arm/mach-omap2/Makefile        |    2 +
  arch/arm/mach-omap2/board-generic.c |    3 +-
  arch/arm/mach-omap2/common.c        |   28 ++
  arch/arm/mach-omap2/common.h        |   14 +
  arch/arm/mach-omap2/control.c       |   57 ++++
  arch/arm/mach-omap2/control.h       |   54 ++++
  arch/arm/mach-omap2/io.c            |    6 +
  arch/arm/mach-omap2/omap_device.c   |    8 +
  arch/arm/mach-omap2/omap_device.h   |    2 +
  arch/arm/mach-omap2/pm.c            |    3 +-
  arch/arm/mach-omap2/pm.h            |    5 +
  arch/arm/mach-omap2/pm33xx.c        |  474 +++++++++++++++++++++++++++++
  arch/arm/mach-omap2/pm33xx.h        |   77 +++++
  arch/arm/mach-omap2/sleep33xx.S     |  350 ++++++++++++++++++++++
  arch/arm/mach-omap2/sram.c          |   10 +-
  arch/arm/mach-omap2/sram.h          |    2 +
  arch/arm/mach-omap2/timer.c         |   32 ++
  arch/arm/mach-omap2/wkup_m3.c       |  183 ++++++++++++
  drivers/memory/emif.h               |  543 +---------------------------------
  include/linux/ti_emif.h             |  558 +++++++++++++++++++++++++++++++++++
  22 files changed, 1872 insertions(+), 547 deletions(-)

create mode 100644 arch/arm/mach-omap2/pm33xx.c create mode 100644 arch/arm/mach-omap2/pm33xx.h create mode 100644 arch/arm/mach-omap2/sleep33xx.S create mode 100644 arch/arm/mach-omap2/wkup_m3.c create mode 100644 include/linux/ti_emif.h

#95 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Hi Dave,

Quoted 24 lines · Dave Gerlach
Quoted 23 lines · Gururaja Hebbar
Quoted 15 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Quoted 4 lines

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

can you share the working repo which has all these patches applied?

Quoted 7 lines
Quoted 3 lines

Thanks & Regards
Gururaja

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Kevin

#96 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 36 lines · Kevin Hilman

Hi Dave,

Quoted 24 lines · Dave Gerlach
Quoted 23 lines · Gururaja Hebbar
Quoted 15 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Quoted 4 lines

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

can you share the working repo which has all these patches applied?

Quoted 7 lines
Quoted 3 lines

Thanks & Regards
Gururaja

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

Quoted 9 lines

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

Regards,
Dave

#97 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 44 lines · Dave Gerlach
Quoted 43 lines · Kevin Hilman

Hi Dave,

Quoted 24 lines · Dave Gerlach
Quoted 23 lines · Gururaja Hebbar
Quoted 15 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Quoted 4 lines

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

can you share the working repo which has all these patches applied?

Quoted 7 lines
Quoted 3 lines

Thanks & Regards
Gururaja

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Quoted 7 lines
Quoted 2 lines

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

OK, I didn't realize that. I'll give it a try on my BB white.

Is there a specific version/branch of the firmware I should be using?

Thanks,

Kevin

#98 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 54 lines · Kevin Hilman
Quoted 44 lines · Dave Gerlach
Quoted 43 lines · Kevin Hilman

Hi Dave,

Quoted 24 lines · Dave Gerlach
Quoted 23 lines · Gururaja Hebbar
Quoted 15 lines · Dave Gerlach

Hi,

This is the third version of the patch series for adding basic suspend-resume support for AM33XX, previously submitted by Vaibhav Bedia. This patchset is based on 3.11-rc4 and depends on a forthcoming patchset from Suman Anna that adds mailbox support for the wkup_m3. The patches at [1], [2], and [3] are required for the pm code to properly suspend and resume.

The PM code uses the firmware interface and expects the userspace to load the WKUP_M3 binary before the suspend-resume functionality is made available. The binary file (and the source-code for WKUP_M3) can be obtained from the 'next2' branch at [4]. The WKUP_M3 binary can either be loaded post bootup via the sysfs entry './sys/devices/ocp.2/wkup_m3.4/firmware' or it can be included in the kernel image as part of the build process.

Quoted 4 lines

Suspend to mem is tested on am335x-bone and am335x-evm.

More details on AM335x suspend-resume are provided within the commit logs for each patch.

can you share the working repo which has all these patches applied?

Quoted 7 lines
Quoted 3 lines

Thanks & Regards
Gururaja

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Quoted 7 lines
Quoted 2 lines

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

Quoted 8 lines

OK, I didn't realize that. I'll give it a try on my BB white.

Is there a specific version/branch of the firmware I should be using?

Thanks,

Kevin

Kevin,

The next2 branch, which you can find here [1], is what this revision of the series was developed against and is tested and works.

Regards,
Dave

[1]
http://arago-project.org/git/projects/?p=am33x-cm3.git;a=shortlog;h=refs/heads/next2

#99 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

In reply to Dave Gerlach

Dave Gerlach <[email protected]> writes:

[...]

Quoted 12 lines
Quoted 12 lines
Quoted 4 lines

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Quoted 7 lines
Quoted 2 lines

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

OK, I tried the above branch on my BB white, using prebuilt firmware from the next3 branch of the am33x-cm3 repo and it's suspending/resuming fine. Thanks for the pointer.

FYI, measuring at the 5V supply, it goes from ~1.6W at idle down to ~700mW in suspend. The black goes from ~1W down to an impressive 130mW but of course, it doesn't wake up so maybe it's not that impressive. ;)

Kevin

#100 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 24 lines · Kevin Hilman

Dave Gerlach <[email protected]> writes:

[...]

Quoted 12 lines
Quoted 12 lines
Quoted 4 lines

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Quoted 7 lines
Quoted 2 lines

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

Quoted 7 lines

OK, I tried the above branch on my BB white, using prebuilt firmware from the next3 branch of the am33x-cm3 repo and it's suspending/resuming fine. Thanks for the pointer.

FYI, measuring at the 5V supply, it goes from ~1.6W at idle down to ~700mW in suspend. The black goes from ~1W down to an impressive 130mW but of course, it doesn't wake up so maybe it's not that impressive. ;)

Just a reminder, the next3 firmware is built to be compatible with older kernel revisions whereas the next2 firmware is not. In order for that compatibility to work, the CMD_ID_DS0 that mainline uses should change from 0x3 to 0x4

#101 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 29 lines · Russ Dill
Quoted 28 lines · Kevin Hilman

Dave Gerlach <[email protected]> writes:

[...]

Quoted 12 lines
Quoted 12 lines
Quoted 4 lines

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Quoted 7 lines
Quoted 2 lines

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

OK, I tried the above branch on my BB white, using prebuilt firmware from the next3 branch of the am33x-cm3 repo and it's suspending/resuming fine. Thanks for the pointer.

Quoted 8 lines
Quoted 3 lines

FYI, measuring at the 5V supply, it goes from ~1.6W at idle down to ~700mW in suspend. The black goes from ~1W down to an impressive 130mW but of course, it doesn't wake up so maybe it's not that impressive. ;)

Just a reminder, the next3 firmware is built to be compatible with older kernel revisions whereas the next2 firmware is not. In order for that compatibility to work, the CMD_ID_DS0 that mainline uses should change from 0x3 to 0x4

Thanks, i switched to the next2 firmware since I'm only using current kernels.

Kevin

#102 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 34 lines · Kevin Hilman
Quoted 33 lines · Russ Dill
Quoted 31 lines · Kevin Hilman

Dave Gerlach <[email protected]> writes:

[...]

Quoted 12 lines
Quoted 12 lines
Quoted 4 lines

The working repo for this version of the patch series can be found here:

git://github.com/dgerlach/linux-pm.git am335x-3.11rc4-suspend-resume

I tried this branch on my beaglebone black, and it's not fully resuming. Suspend seems to be working (power draw goes from ~1W to ~130mW) and pressing a key on the UART seems to be waking up the SoC (power draw goes to ~600mW) but I don't ever get the console back.

Is there a specific version of the firmware I should be using?

Quoted 7 lines
Quoted 2 lines

Kevin

Kevin, I agree there does seem to be some issues with Beaglebone black. I can confirm it works on BeagleBone White and the large am335 EVM, I am working on pinpointing the issue on beaglebone black, seems that support isn't quite there yet.

OK, I tried the above branch on my BB white, using prebuilt firmware from the next3 branch of the am33x-cm3 repo and it's suspending/resuming fine. Thanks for the pointer.

FYI, measuring at the 5V supply, it goes from ~1.6W at idle down to ~700mW in suspend. The black goes from ~1W down to an impressive 130mW but of course, it doesn't wake up so maybe it's not that impressive. ;)

Quoted 9 lines
Quoted 4 lines

Just a reminder, the next3 firmware is built to be compatible with older kernel revisions whereas the next2 firmware is not. In order for that compatibility to work, the CMD_ID_DS0 that mainline uses should change from 0x3 to 0x4

Thanks, i switched to the next2 firmware since I'm only using current kernels.

Kevin

Kevin,
Thanks for taking the time to try this out, it does seem there are a few kinks with BeagleBone Black but we'll get those worked out.

Regards,
Dave

#103 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Hi Dave,

Quoted 2 lines

Thanks for taking the time to try this out, it does seem there are a few kinks with BeagleBone Black but we'll get those worked out.

I also just noticed that wake from RTC isn't working, but wake from serial console does. Does RTC wake work for you? (I use rtcwake -m mem -s4)

Kevin

#104 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 10 lines · Kevin Hilman

Hi Dave,

Quoted 2 lines

Thanks for taking the time to try this out, it does seem there are a few kinks with BeagleBone Black but we'll get those worked out.

I also just noticed that wake from RTC isn't working, but wake from serial console does. Does RTC wake work for you? (I use rtcwake -m mem -s4)

Kevin

On Beaglebone white or black? For PG 1.0 (Beaglebone white) there is the following errata:

"RTC: 32.768-kHZ Clock is Gating Off"

Details The RTC has a clock gating issue that stops the internal 32.768-kHz clock when the VDD_CORE voltage domain drops below the recommended operating range or the PWRONRSTn input terminal is held low. This issue has the following side effects:

- The RTC counters stop incrementing when the 32.768-kHz clock is gated. This causes the RTC to lose time while the clock is gated.

- A wakeup event applied to the EXT_WAKEUP input terminal is masked if the EXT_WAKEUP_DB_EN bit in the RTC PMIC register (0x98) is set to 1 which enables the de-bounce function for the EXT_WAKEUP input. This occurs because the 32.768-kHz clock is being used to clock the de-bounce circuit.

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#105 lore raw

v3 cover ARM: OMAP2+: AM33XX: Add suspend-resume support

Quoted 6 lines · Russ Dill
Quoted 5 lines · Kevin Hilman

Hi Dave,

Quoted 2 lines

Thanks for taking the time to try this out, it does seem there are a few kinks with BeagleBone Black but we'll get those worked out.

Quoted 7 lines
Quoted 5 lines

I also just noticed that wake from RTC isn't working, but wake from serial console does. Does RTC wake work for you? (I use rtcwake -m mem -s4)

Kevin

On Beaglebone white or black?

White.

Quoted 10 lines

For PG 1.0 (Beaglebone white) there is
the following errata:

"RTC: 32.768-kHZ Clock is Gating Off"

Details The RTC has a clock gating issue that stops the internal 32.768-kHz clock when the VDD_CORE voltage domain drops below the recommended operating range or the PWRONRSTn input terminal is held low. This issue has the following side effects:

Quoted 8 lines

- The RTC counters stop incrementing when the 32.768-kHz clock is gated. This causes the RTC to lose time while the clock is gated.

- A wakeup event applied to the EXT_WAKEUP input terminal is masked if the EXT_WAKEUP_DB_EN bit in the RTC PMIC register (0x98) is set to 1 which enables the de-bounce function for the EXT_WAKEUP input. This occurs because the 32.768-kHz clock is being used to clock the de-bounce circuit.

I'm not using your VDD_CORE scaling series (or maybe the firmware is scaling VDD_CORE?)

Anyways, thanks for the info on the errata, that must be what's causing it.

Kevin