1650c2a21SLinus Walleij /* 2650c2a21SLinus Walleij * Copyright (C) STMicroelectronics 2009 3650c2a21SLinus Walleij * Copyright (C) ST-Ericsson SA 2010 4650c2a21SLinus Walleij * 5650c2a21SLinus Walleij * License Terms: GNU General Public License v2 6650c2a21SLinus Walleij * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> 7650c2a21SLinus Walleij * Author: Sundar Iyer <sundar.iyer@stericsson.com> 8650c2a21SLinus Walleij * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> 9650c2a21SLinus Walleij * 10650c2a21SLinus Walleij * U8500 PRCM Unit interface driver 11650c2a21SLinus Walleij * 12650c2a21SLinus Walleij */ 13650c2a21SLinus Walleij #include <linux/module.h> 143df57bcfSMattias Nilsson #include <linux/kernel.h> 153df57bcfSMattias Nilsson #include <linux/delay.h> 16650c2a21SLinus Walleij #include <linux/errno.h> 17650c2a21SLinus Walleij #include <linux/err.h> 183df57bcfSMattias Nilsson #include <linux/spinlock.h> 19650c2a21SLinus Walleij #include <linux/io.h> 203df57bcfSMattias Nilsson #include <linux/slab.h> 21650c2a21SLinus Walleij #include <linux/mutex.h> 22650c2a21SLinus Walleij #include <linux/completion.h> 233df57bcfSMattias Nilsson #include <linux/irq.h> 24650c2a21SLinus Walleij #include <linux/jiffies.h> 25650c2a21SLinus Walleij #include <linux/bitops.h> 263df57bcfSMattias Nilsson #include <linux/fs.h> 273df57bcfSMattias Nilsson #include <linux/platform_device.h> 283df57bcfSMattias Nilsson #include <linux/uaccess.h> 293df57bcfSMattias Nilsson #include <linux/mfd/core.h> 30650c2a21SLinus Walleij #include <linux/mfd/db8500-prcmu.h> 311032fbfdSBengt Jonsson #include <linux/regulator/db8500-prcmu.h> 321032fbfdSBengt Jonsson #include <linux/regulator/machine.h> 33650c2a21SLinus Walleij #include <mach/hardware.h> 343df57bcfSMattias Nilsson #include <mach/irqs.h> 353df57bcfSMattias Nilsson #include <mach/db8500-regs.h> 363df57bcfSMattias Nilsson #include <mach/id.h> 37650c2a21SLinus Walleij #include "db8500-prcmu-regs.h" 38650c2a21SLinus Walleij 393df57bcfSMattias Nilsson /* Offset for the firmware version within the TCPM */ 403df57bcfSMattias Nilsson #define PRCMU_FW_VERSION_OFFSET 0xA4 41650c2a21SLinus Walleij 423df57bcfSMattias Nilsson /* PRCMU project numbers, defined by PRCMU FW */ 433df57bcfSMattias Nilsson #define PRCMU_PROJECT_ID_8500V1_0 1 443df57bcfSMattias Nilsson #define PRCMU_PROJECT_ID_8500V2_0 2 453df57bcfSMattias Nilsson #define PRCMU_PROJECT_ID_8400V2_0 3 46650c2a21SLinus Walleij 473df57bcfSMattias Nilsson /* Index of different voltages to be used when accessing AVSData */ 483df57bcfSMattias Nilsson #define PRCM_AVS_BASE 0x2FC 493df57bcfSMattias Nilsson #define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0) 503df57bcfSMattias Nilsson #define PRCM_AVS_VBB_MAX_OPP (PRCM_AVS_BASE + 0x1) 513df57bcfSMattias Nilsson #define PRCM_AVS_VBB_100_OPP (PRCM_AVS_BASE + 0x2) 523df57bcfSMattias Nilsson #define PRCM_AVS_VBB_50_OPP (PRCM_AVS_BASE + 0x3) 533df57bcfSMattias Nilsson #define PRCM_AVS_VARM_MAX_OPP (PRCM_AVS_BASE + 0x4) 543df57bcfSMattias Nilsson #define PRCM_AVS_VARM_100_OPP (PRCM_AVS_BASE + 0x5) 553df57bcfSMattias Nilsson #define PRCM_AVS_VARM_50_OPP (PRCM_AVS_BASE + 0x6) 563df57bcfSMattias Nilsson #define PRCM_AVS_VARM_RET (PRCM_AVS_BASE + 0x7) 573df57bcfSMattias Nilsson #define PRCM_AVS_VAPE_100_OPP (PRCM_AVS_BASE + 0x8) 583df57bcfSMattias Nilsson #define PRCM_AVS_VAPE_50_OPP (PRCM_AVS_BASE + 0x9) 593df57bcfSMattias Nilsson #define PRCM_AVS_VMOD_100_OPP (PRCM_AVS_BASE + 0xA) 603df57bcfSMattias Nilsson #define PRCM_AVS_VMOD_50_OPP (PRCM_AVS_BASE + 0xB) 613df57bcfSMattias Nilsson #define PRCM_AVS_VSAFE (PRCM_AVS_BASE + 0xC) 62650c2a21SLinus Walleij 633df57bcfSMattias Nilsson #define PRCM_AVS_VOLTAGE 0 643df57bcfSMattias Nilsson #define PRCM_AVS_VOLTAGE_MASK 0x3f 653df57bcfSMattias Nilsson #define PRCM_AVS_ISSLOWSTARTUP 6 663df57bcfSMattias Nilsson #define PRCM_AVS_ISSLOWSTARTUP_MASK (1 << PRCM_AVS_ISSLOWSTARTUP) 67650c2a21SLinus Walleij #define PRCM_AVS_ISMODEENABLE 7 68650c2a21SLinus Walleij #define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE) 69650c2a21SLinus Walleij 703df57bcfSMattias Nilsson #define PRCM_BOOT_STATUS 0xFFF 713df57bcfSMattias Nilsson #define PRCM_ROMCODE_A2P 0xFFE 723df57bcfSMattias Nilsson #define PRCM_ROMCODE_P2A 0xFFD 733df57bcfSMattias Nilsson #define PRCM_XP70_CUR_PWR_STATE 0xFFC /* 4 BYTES */ 74650c2a21SLinus Walleij 753df57bcfSMattias Nilsson #define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */ 763df57bcfSMattias Nilsson 773df57bcfSMattias Nilsson #define _PRCM_MBOX_HEADER 0xFE8 /* 16 bytes */ 783df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_REQ_MB0 (_PRCM_MBOX_HEADER + 0x0) 793df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_REQ_MB1 (_PRCM_MBOX_HEADER + 0x1) 803df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_REQ_MB2 (_PRCM_MBOX_HEADER + 0x2) 813df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_REQ_MB3 (_PRCM_MBOX_HEADER + 0x3) 823df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_REQ_MB4 (_PRCM_MBOX_HEADER + 0x4) 833df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5) 843df57bcfSMattias Nilsson #define PRCM_MBOX_HEADER_ACK_MB0 (_PRCM_MBOX_HEADER + 0x8) 853df57bcfSMattias Nilsson 863df57bcfSMattias Nilsson /* Req Mailboxes */ 873df57bcfSMattias Nilsson #define PRCM_REQ_MB0 0xFDC /* 12 bytes */ 883df57bcfSMattias Nilsson #define PRCM_REQ_MB1 0xFD0 /* 12 bytes */ 893df57bcfSMattias Nilsson #define PRCM_REQ_MB2 0xFC0 /* 16 bytes */ 903df57bcfSMattias Nilsson #define PRCM_REQ_MB3 0xE4C /* 372 bytes */ 913df57bcfSMattias Nilsson #define PRCM_REQ_MB4 0xE48 /* 4 bytes */ 923df57bcfSMattias Nilsson #define PRCM_REQ_MB5 0xE44 /* 4 bytes */ 933df57bcfSMattias Nilsson 943df57bcfSMattias Nilsson /* Ack Mailboxes */ 953df57bcfSMattias Nilsson #define PRCM_ACK_MB0 0xE08 /* 52 bytes */ 963df57bcfSMattias Nilsson #define PRCM_ACK_MB1 0xE04 /* 4 bytes */ 973df57bcfSMattias Nilsson #define PRCM_ACK_MB2 0xE00 /* 4 bytes */ 983df57bcfSMattias Nilsson #define PRCM_ACK_MB3 0xDFC /* 4 bytes */ 993df57bcfSMattias Nilsson #define PRCM_ACK_MB4 0xDF8 /* 4 bytes */ 1003df57bcfSMattias Nilsson #define PRCM_ACK_MB5 0xDF4 /* 4 bytes */ 1013df57bcfSMattias Nilsson 1023df57bcfSMattias Nilsson /* Mailbox 0 headers */ 1033df57bcfSMattias Nilsson #define MB0H_POWER_STATE_TRANS 0 1043df57bcfSMattias Nilsson #define MB0H_CONFIG_WAKEUPS_EXE 1 1053df57bcfSMattias Nilsson #define MB0H_READ_WAKEUP_ACK 3 1063df57bcfSMattias Nilsson #define MB0H_CONFIG_WAKEUPS_SLEEP 4 1073df57bcfSMattias Nilsson 1083df57bcfSMattias Nilsson #define MB0H_WAKEUP_EXE 2 1093df57bcfSMattias Nilsson #define MB0H_WAKEUP_SLEEP 5 1103df57bcfSMattias Nilsson 1113df57bcfSMattias Nilsson /* Mailbox 0 REQs */ 1123df57bcfSMattias Nilsson #define PRCM_REQ_MB0_AP_POWER_STATE (PRCM_REQ_MB0 + 0x0) 1133df57bcfSMattias Nilsson #define PRCM_REQ_MB0_AP_PLL_STATE (PRCM_REQ_MB0 + 0x1) 1143df57bcfSMattias Nilsson #define PRCM_REQ_MB0_ULP_CLOCK_STATE (PRCM_REQ_MB0 + 0x2) 1153df57bcfSMattias Nilsson #define PRCM_REQ_MB0_DO_NOT_WFI (PRCM_REQ_MB0 + 0x3) 1163df57bcfSMattias Nilsson #define PRCM_REQ_MB0_WAKEUP_8500 (PRCM_REQ_MB0 + 0x4) 1173df57bcfSMattias Nilsson #define PRCM_REQ_MB0_WAKEUP_4500 (PRCM_REQ_MB0 + 0x8) 1183df57bcfSMattias Nilsson 1193df57bcfSMattias Nilsson /* Mailbox 0 ACKs */ 1203df57bcfSMattias Nilsson #define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0) 1213df57bcfSMattias Nilsson #define PRCM_ACK_MB0_READ_POINTER (PRCM_ACK_MB0 + 0x1) 1223df57bcfSMattias Nilsson #define PRCM_ACK_MB0_WAKEUP_0_8500 (PRCM_ACK_MB0 + 0x4) 1233df57bcfSMattias Nilsson #define PRCM_ACK_MB0_WAKEUP_0_4500 (PRCM_ACK_MB0 + 0x8) 1243df57bcfSMattias Nilsson #define PRCM_ACK_MB0_WAKEUP_1_8500 (PRCM_ACK_MB0 + 0x1C) 1253df57bcfSMattias Nilsson #define PRCM_ACK_MB0_WAKEUP_1_4500 (PRCM_ACK_MB0 + 0x20) 1263df57bcfSMattias Nilsson #define PRCM_ACK_MB0_EVENT_4500_NUMBERS 20 1273df57bcfSMattias Nilsson 1283df57bcfSMattias Nilsson /* Mailbox 1 headers */ 1293df57bcfSMattias Nilsson #define MB1H_ARM_APE_OPP 0x0 1303df57bcfSMattias Nilsson #define MB1H_RESET_MODEM 0x2 1313df57bcfSMattias Nilsson #define MB1H_REQUEST_APE_OPP_100_VOLT 0x3 1323df57bcfSMattias Nilsson #define MB1H_RELEASE_APE_OPP_100_VOLT 0x4 1333df57bcfSMattias Nilsson #define MB1H_RELEASE_USB_WAKEUP 0x5 1343df57bcfSMattias Nilsson 1353df57bcfSMattias Nilsson /* Mailbox 1 Requests */ 1363df57bcfSMattias Nilsson #define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0) 1373df57bcfSMattias Nilsson #define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1) 1383df57bcfSMattias Nilsson #define PRCM_REQ_MB1_APE_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x4) 1393df57bcfSMattias Nilsson #define PRCM_REQ_MB1_ARM_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x8) 1403df57bcfSMattias Nilsson 1413df57bcfSMattias Nilsson /* Mailbox 1 ACKs */ 1423df57bcfSMattias Nilsson #define PRCM_ACK_MB1_CURRENT_ARM_OPP (PRCM_ACK_MB1 + 0x0) 1433df57bcfSMattias Nilsson #define PRCM_ACK_MB1_CURRENT_APE_OPP (PRCM_ACK_MB1 + 0x1) 1443df57bcfSMattias Nilsson #define PRCM_ACK_MB1_APE_VOLTAGE_STATUS (PRCM_ACK_MB1 + 0x2) 1453df57bcfSMattias Nilsson #define PRCM_ACK_MB1_DVFS_STATUS (PRCM_ACK_MB1 + 0x3) 1463df57bcfSMattias Nilsson 1473df57bcfSMattias Nilsson /* Mailbox 2 headers */ 1483df57bcfSMattias Nilsson #define MB2H_DPS 0x0 1493df57bcfSMattias Nilsson #define MB2H_AUTO_PWR 0x1 1503df57bcfSMattias Nilsson 1513df57bcfSMattias Nilsson /* Mailbox 2 REQs */ 1523df57bcfSMattias Nilsson #define PRCM_REQ_MB2_SVA_MMDSP (PRCM_REQ_MB2 + 0x0) 1533df57bcfSMattias Nilsson #define PRCM_REQ_MB2_SVA_PIPE (PRCM_REQ_MB2 + 0x1) 1543df57bcfSMattias Nilsson #define PRCM_REQ_MB2_SIA_MMDSP (PRCM_REQ_MB2 + 0x2) 1553df57bcfSMattias Nilsson #define PRCM_REQ_MB2_SIA_PIPE (PRCM_REQ_MB2 + 0x3) 1563df57bcfSMattias Nilsson #define PRCM_REQ_MB2_SGA (PRCM_REQ_MB2 + 0x4) 1573df57bcfSMattias Nilsson #define PRCM_REQ_MB2_B2R2_MCDE (PRCM_REQ_MB2 + 0x5) 1583df57bcfSMattias Nilsson #define PRCM_REQ_MB2_ESRAM12 (PRCM_REQ_MB2 + 0x6) 1593df57bcfSMattias Nilsson #define PRCM_REQ_MB2_ESRAM34 (PRCM_REQ_MB2 + 0x7) 1603df57bcfSMattias Nilsson #define PRCM_REQ_MB2_AUTO_PM_SLEEP (PRCM_REQ_MB2 + 0x8) 1613df57bcfSMattias Nilsson #define PRCM_REQ_MB2_AUTO_PM_IDLE (PRCM_REQ_MB2 + 0xC) 1623df57bcfSMattias Nilsson 1633df57bcfSMattias Nilsson /* Mailbox 2 ACKs */ 1643df57bcfSMattias Nilsson #define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0) 1653df57bcfSMattias Nilsson #define HWACC_PWR_ST_OK 0xFE 1663df57bcfSMattias Nilsson 1673df57bcfSMattias Nilsson /* Mailbox 3 headers */ 1683df57bcfSMattias Nilsson #define MB3H_ANC 0x0 1693df57bcfSMattias Nilsson #define MB3H_SIDETONE 0x1 1703df57bcfSMattias Nilsson #define MB3H_SYSCLK 0xE 1713df57bcfSMattias Nilsson 1723df57bcfSMattias Nilsson /* Mailbox 3 Requests */ 1733df57bcfSMattias Nilsson #define PRCM_REQ_MB3_ANC_FIR_COEFF (PRCM_REQ_MB3 + 0x0) 1743df57bcfSMattias Nilsson #define PRCM_REQ_MB3_ANC_IIR_COEFF (PRCM_REQ_MB3 + 0x20) 1753df57bcfSMattias Nilsson #define PRCM_REQ_MB3_ANC_SHIFTER (PRCM_REQ_MB3 + 0x60) 1763df57bcfSMattias Nilsson #define PRCM_REQ_MB3_ANC_WARP (PRCM_REQ_MB3 + 0x64) 1773df57bcfSMattias Nilsson #define PRCM_REQ_MB3_SIDETONE_FIR_GAIN (PRCM_REQ_MB3 + 0x68) 1783df57bcfSMattias Nilsson #define PRCM_REQ_MB3_SIDETONE_FIR_COEFF (PRCM_REQ_MB3 + 0x6C) 1793df57bcfSMattias Nilsson #define PRCM_REQ_MB3_SYSCLK_MGT (PRCM_REQ_MB3 + 0x16C) 1803df57bcfSMattias Nilsson 1813df57bcfSMattias Nilsson /* Mailbox 4 headers */ 1823df57bcfSMattias Nilsson #define MB4H_DDR_INIT 0x0 1833df57bcfSMattias Nilsson #define MB4H_MEM_ST 0x1 1843df57bcfSMattias Nilsson #define MB4H_HOTDOG 0x12 1853df57bcfSMattias Nilsson #define MB4H_HOTMON 0x13 1863df57bcfSMattias Nilsson #define MB4H_HOT_PERIOD 0x14 1873df57bcfSMattias Nilsson 1883df57bcfSMattias Nilsson /* Mailbox 4 Requests */ 1893df57bcfSMattias Nilsson #define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE (PRCM_REQ_MB4 + 0x0) 1903df57bcfSMattias Nilsson #define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE (PRCM_REQ_MB4 + 0x1) 1913df57bcfSMattias Nilsson #define PRCM_REQ_MB4_ESRAM0_ST (PRCM_REQ_MB4 + 0x3) 1923df57bcfSMattias Nilsson #define PRCM_REQ_MB4_HOTDOG_THRESHOLD (PRCM_REQ_MB4 + 0x0) 1933df57bcfSMattias Nilsson #define PRCM_REQ_MB4_HOTMON_LOW (PRCM_REQ_MB4 + 0x0) 1943df57bcfSMattias Nilsson #define PRCM_REQ_MB4_HOTMON_HIGH (PRCM_REQ_MB4 + 0x1) 1953df57bcfSMattias Nilsson #define PRCM_REQ_MB4_HOTMON_CONFIG (PRCM_REQ_MB4 + 0x2) 1963df57bcfSMattias Nilsson #define PRCM_REQ_MB4_HOT_PERIOD (PRCM_REQ_MB4 + 0x0) 1973df57bcfSMattias Nilsson #define HOTMON_CONFIG_LOW BIT(0) 1983df57bcfSMattias Nilsson #define HOTMON_CONFIG_HIGH BIT(1) 1993df57bcfSMattias Nilsson 2003df57bcfSMattias Nilsson /* Mailbox 5 Requests */ 2013df57bcfSMattias Nilsson #define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0) 2023df57bcfSMattias Nilsson #define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1) 2033df57bcfSMattias Nilsson #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2) 2043df57bcfSMattias Nilsson #define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3) 2053df57bcfSMattias Nilsson #define PRCMU_I2C_WRITE(slave) \ 2063df57bcfSMattias Nilsson (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0)) 2073df57bcfSMattias Nilsson #define PRCMU_I2C_READ(slave) \ 2083df57bcfSMattias Nilsson (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0)) 2093df57bcfSMattias Nilsson #define PRCMU_I2C_STOP_EN BIT(3) 2103df57bcfSMattias Nilsson 2113df57bcfSMattias Nilsson /* Mailbox 5 ACKs */ 2123df57bcfSMattias Nilsson #define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1) 2133df57bcfSMattias Nilsson #define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3) 2143df57bcfSMattias Nilsson #define I2C_WR_OK 0x1 2153df57bcfSMattias Nilsson #define I2C_RD_OK 0x2 2163df57bcfSMattias Nilsson 2173df57bcfSMattias Nilsson #define NUM_MB 8 2183df57bcfSMattias Nilsson #define MBOX_BIT BIT 2193df57bcfSMattias Nilsson #define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1) 2203df57bcfSMattias Nilsson 2213df57bcfSMattias Nilsson /* 2223df57bcfSMattias Nilsson * Wakeups/IRQs 2233df57bcfSMattias Nilsson */ 2243df57bcfSMattias Nilsson 2253df57bcfSMattias Nilsson #define WAKEUP_BIT_RTC BIT(0) 2263df57bcfSMattias Nilsson #define WAKEUP_BIT_RTT0 BIT(1) 2273df57bcfSMattias Nilsson #define WAKEUP_BIT_RTT1 BIT(2) 2283df57bcfSMattias Nilsson #define WAKEUP_BIT_HSI0 BIT(3) 2293df57bcfSMattias Nilsson #define WAKEUP_BIT_HSI1 BIT(4) 2303df57bcfSMattias Nilsson #define WAKEUP_BIT_CA_WAKE BIT(5) 2313df57bcfSMattias Nilsson #define WAKEUP_BIT_USB BIT(6) 2323df57bcfSMattias Nilsson #define WAKEUP_BIT_ABB BIT(7) 2333df57bcfSMattias Nilsson #define WAKEUP_BIT_ABB_FIFO BIT(8) 2343df57bcfSMattias Nilsson #define WAKEUP_BIT_SYSCLK_OK BIT(9) 2353df57bcfSMattias Nilsson #define WAKEUP_BIT_CA_SLEEP BIT(10) 2363df57bcfSMattias Nilsson #define WAKEUP_BIT_AC_WAKE_ACK BIT(11) 2373df57bcfSMattias Nilsson #define WAKEUP_BIT_SIDE_TONE_OK BIT(12) 2383df57bcfSMattias Nilsson #define WAKEUP_BIT_ANC_OK BIT(13) 2393df57bcfSMattias Nilsson #define WAKEUP_BIT_SW_ERROR BIT(14) 2403df57bcfSMattias Nilsson #define WAKEUP_BIT_AC_SLEEP_ACK BIT(15) 2413df57bcfSMattias Nilsson #define WAKEUP_BIT_ARM BIT(17) 2423df57bcfSMattias Nilsson #define WAKEUP_BIT_HOTMON_LOW BIT(18) 2433df57bcfSMattias Nilsson #define WAKEUP_BIT_HOTMON_HIGH BIT(19) 2443df57bcfSMattias Nilsson #define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20) 2453df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO0 BIT(23) 2463df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO1 BIT(24) 2473df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO2 BIT(25) 2483df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO3 BIT(26) 2493df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO4 BIT(27) 2503df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO5 BIT(28) 2513df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO6 BIT(29) 2523df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO7 BIT(30) 2533df57bcfSMattias Nilsson #define WAKEUP_BIT_GPIO8 BIT(31) 2543df57bcfSMattias Nilsson 2553df57bcfSMattias Nilsson /* 2563df57bcfSMattias Nilsson * This vector maps irq numbers to the bits in the bit field used in 2573df57bcfSMattias Nilsson * communication with the PRCMU firmware. 2583df57bcfSMattias Nilsson * 2593df57bcfSMattias Nilsson * The reason for having this is to keep the irq numbers contiguous even though 2603df57bcfSMattias Nilsson * the bits in the bit field are not. (The bits also have a tendency to move 2613df57bcfSMattias Nilsson * around, to further complicate matters.) 2623df57bcfSMattias Nilsson */ 2633df57bcfSMattias Nilsson #define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE) 2643df57bcfSMattias Nilsson #define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name) 2653df57bcfSMattias Nilsson static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = { 2663df57bcfSMattias Nilsson IRQ_ENTRY(RTC), 2673df57bcfSMattias Nilsson IRQ_ENTRY(RTT0), 2683df57bcfSMattias Nilsson IRQ_ENTRY(RTT1), 2693df57bcfSMattias Nilsson IRQ_ENTRY(HSI0), 2703df57bcfSMattias Nilsson IRQ_ENTRY(HSI1), 2713df57bcfSMattias Nilsson IRQ_ENTRY(CA_WAKE), 2723df57bcfSMattias Nilsson IRQ_ENTRY(USB), 2733df57bcfSMattias Nilsson IRQ_ENTRY(ABB), 2743df57bcfSMattias Nilsson IRQ_ENTRY(ABB_FIFO), 2753df57bcfSMattias Nilsson IRQ_ENTRY(CA_SLEEP), 2763df57bcfSMattias Nilsson IRQ_ENTRY(ARM), 2773df57bcfSMattias Nilsson IRQ_ENTRY(HOTMON_LOW), 2783df57bcfSMattias Nilsson IRQ_ENTRY(HOTMON_HIGH), 2793df57bcfSMattias Nilsson IRQ_ENTRY(MODEM_SW_RESET_REQ), 2803df57bcfSMattias Nilsson IRQ_ENTRY(GPIO0), 2813df57bcfSMattias Nilsson IRQ_ENTRY(GPIO1), 2823df57bcfSMattias Nilsson IRQ_ENTRY(GPIO2), 2833df57bcfSMattias Nilsson IRQ_ENTRY(GPIO3), 2843df57bcfSMattias Nilsson IRQ_ENTRY(GPIO4), 2853df57bcfSMattias Nilsson IRQ_ENTRY(GPIO5), 2863df57bcfSMattias Nilsson IRQ_ENTRY(GPIO6), 2873df57bcfSMattias Nilsson IRQ_ENTRY(GPIO7), 2883df57bcfSMattias Nilsson IRQ_ENTRY(GPIO8) 289650c2a21SLinus Walleij }; 290650c2a21SLinus Walleij 2913df57bcfSMattias Nilsson #define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1) 2923df57bcfSMattias Nilsson #define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name) 2933df57bcfSMattias Nilsson static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = { 2943df57bcfSMattias Nilsson WAKEUP_ENTRY(RTC), 2953df57bcfSMattias Nilsson WAKEUP_ENTRY(RTT0), 2963df57bcfSMattias Nilsson WAKEUP_ENTRY(RTT1), 2973df57bcfSMattias Nilsson WAKEUP_ENTRY(HSI0), 2983df57bcfSMattias Nilsson WAKEUP_ENTRY(HSI1), 2993df57bcfSMattias Nilsson WAKEUP_ENTRY(USB), 3003df57bcfSMattias Nilsson WAKEUP_ENTRY(ABB), 3013df57bcfSMattias Nilsson WAKEUP_ENTRY(ABB_FIFO), 3023df57bcfSMattias Nilsson WAKEUP_ENTRY(ARM) 3033df57bcfSMattias Nilsson }; 3043df57bcfSMattias Nilsson 3053df57bcfSMattias Nilsson /* 3063df57bcfSMattias Nilsson * mb0_transfer - state needed for mailbox 0 communication. 3073df57bcfSMattias Nilsson * @lock: The transaction lock. 3083df57bcfSMattias Nilsson * @dbb_events_lock: A lock used to handle concurrent access to (parts of) 3093df57bcfSMattias Nilsson * the request data. 3103df57bcfSMattias Nilsson * @mask_work: Work structure used for (un)masking wakeup interrupts. 3113df57bcfSMattias Nilsson * @req: Request data that need to persist between requests. 3123df57bcfSMattias Nilsson */ 3133df57bcfSMattias Nilsson static struct { 3143df57bcfSMattias Nilsson spinlock_t lock; 3153df57bcfSMattias Nilsson spinlock_t dbb_irqs_lock; 3163df57bcfSMattias Nilsson struct work_struct mask_work; 3173df57bcfSMattias Nilsson struct mutex ac_wake_lock; 3183df57bcfSMattias Nilsson struct completion ac_wake_work; 3193df57bcfSMattias Nilsson struct { 3203df57bcfSMattias Nilsson u32 dbb_irqs; 3213df57bcfSMattias Nilsson u32 dbb_wakeups; 3223df57bcfSMattias Nilsson u32 abb_events; 3233df57bcfSMattias Nilsson } req; 3243df57bcfSMattias Nilsson } mb0_transfer; 3253df57bcfSMattias Nilsson 3263df57bcfSMattias Nilsson /* 3273df57bcfSMattias Nilsson * mb1_transfer - state needed for mailbox 1 communication. 3283df57bcfSMattias Nilsson * @lock: The transaction lock. 3293df57bcfSMattias Nilsson * @work: The transaction completion structure. 3303df57bcfSMattias Nilsson * @ack: Reply ("acknowledge") data. 3313df57bcfSMattias Nilsson */ 332650c2a21SLinus Walleij static struct { 333650c2a21SLinus Walleij struct mutex lock; 334650c2a21SLinus Walleij struct completion work; 335650c2a21SLinus Walleij struct { 3363df57bcfSMattias Nilsson u8 header; 337650c2a21SLinus Walleij u8 arm_opp; 338650c2a21SLinus Walleij u8 ape_opp; 3393df57bcfSMattias Nilsson u8 ape_voltage_status; 340650c2a21SLinus Walleij } ack; 341650c2a21SLinus Walleij } mb1_transfer; 342650c2a21SLinus Walleij 3433df57bcfSMattias Nilsson /* 3443df57bcfSMattias Nilsson * mb2_transfer - state needed for mailbox 2 communication. 3453df57bcfSMattias Nilsson * @lock: The transaction lock. 3463df57bcfSMattias Nilsson * @work: The transaction completion structure. 3473df57bcfSMattias Nilsson * @auto_pm_lock: The autonomous power management configuration lock. 3483df57bcfSMattias Nilsson * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled. 3493df57bcfSMattias Nilsson * @req: Request data that need to persist between requests. 3503df57bcfSMattias Nilsson * @ack: Reply ("acknowledge") data. 3513df57bcfSMattias Nilsson */ 352650c2a21SLinus Walleij static struct { 353650c2a21SLinus Walleij struct mutex lock; 354650c2a21SLinus Walleij struct completion work; 3553df57bcfSMattias Nilsson spinlock_t auto_pm_lock; 3563df57bcfSMattias Nilsson bool auto_pm_enabled; 3573df57bcfSMattias Nilsson struct { 3583df57bcfSMattias Nilsson u8 status; 3593df57bcfSMattias Nilsson } ack; 3603df57bcfSMattias Nilsson } mb2_transfer; 3613df57bcfSMattias Nilsson 3623df57bcfSMattias Nilsson /* 3633df57bcfSMattias Nilsson * mb3_transfer - state needed for mailbox 3 communication. 3643df57bcfSMattias Nilsson * @lock: The request lock. 3653df57bcfSMattias Nilsson * @sysclk_lock: A lock used to handle concurrent sysclk requests. 3663df57bcfSMattias Nilsson * @sysclk_work: Work structure used for sysclk requests. 3673df57bcfSMattias Nilsson */ 3683df57bcfSMattias Nilsson static struct { 3693df57bcfSMattias Nilsson spinlock_t lock; 3703df57bcfSMattias Nilsson struct mutex sysclk_lock; 3713df57bcfSMattias Nilsson struct completion sysclk_work; 3723df57bcfSMattias Nilsson } mb3_transfer; 3733df57bcfSMattias Nilsson 3743df57bcfSMattias Nilsson /* 3753df57bcfSMattias Nilsson * mb4_transfer - state needed for mailbox 4 communication. 3763df57bcfSMattias Nilsson * @lock: The transaction lock. 3773df57bcfSMattias Nilsson * @work: The transaction completion structure. 3783df57bcfSMattias Nilsson */ 3793df57bcfSMattias Nilsson static struct { 3803df57bcfSMattias Nilsson struct mutex lock; 3813df57bcfSMattias Nilsson struct completion work; 3823df57bcfSMattias Nilsson } mb4_transfer; 3833df57bcfSMattias Nilsson 3843df57bcfSMattias Nilsson /* 3853df57bcfSMattias Nilsson * mb5_transfer - state needed for mailbox 5 communication. 3863df57bcfSMattias Nilsson * @lock: The transaction lock. 3873df57bcfSMattias Nilsson * @work: The transaction completion structure. 3883df57bcfSMattias Nilsson * @ack: Reply ("acknowledge") data. 3893df57bcfSMattias Nilsson */ 3903df57bcfSMattias Nilsson static struct { 3913df57bcfSMattias Nilsson struct mutex lock; 3923df57bcfSMattias Nilsson struct completion work; 393650c2a21SLinus Walleij struct { 394650c2a21SLinus Walleij u8 status; 395650c2a21SLinus Walleij u8 value; 396650c2a21SLinus Walleij } ack; 397650c2a21SLinus Walleij } mb5_transfer; 398650c2a21SLinus Walleij 3993df57bcfSMattias Nilsson static atomic_t ac_wake_req_state = ATOMIC_INIT(0); 4003df57bcfSMattias Nilsson 4013df57bcfSMattias Nilsson /* Spinlocks */ 4023df57bcfSMattias Nilsson static DEFINE_SPINLOCK(clkout_lock); 4033df57bcfSMattias Nilsson static DEFINE_SPINLOCK(gpiocr_lock); 4043df57bcfSMattias Nilsson 4053df57bcfSMattias Nilsson /* Global var to runtime determine TCDM base for v2 or v1 */ 4063df57bcfSMattias Nilsson static __iomem void *tcdm_base; 4073df57bcfSMattias Nilsson 4083df57bcfSMattias Nilsson struct clk_mgt { 4093df57bcfSMattias Nilsson unsigned int offset; 4103df57bcfSMattias Nilsson u32 pllsw; 4113df57bcfSMattias Nilsson }; 4123df57bcfSMattias Nilsson 4133df57bcfSMattias Nilsson static DEFINE_SPINLOCK(clk_mgt_lock); 4143df57bcfSMattias Nilsson 4153df57bcfSMattias Nilsson #define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 } 4163df57bcfSMattias Nilsson struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { 4173df57bcfSMattias Nilsson CLK_MGT_ENTRY(SGACLK), 4183df57bcfSMattias Nilsson CLK_MGT_ENTRY(UARTCLK), 4193df57bcfSMattias Nilsson CLK_MGT_ENTRY(MSP02CLK), 4203df57bcfSMattias Nilsson CLK_MGT_ENTRY(MSP1CLK), 4213df57bcfSMattias Nilsson CLK_MGT_ENTRY(I2CCLK), 4223df57bcfSMattias Nilsson CLK_MGT_ENTRY(SDMMCCLK), 4233df57bcfSMattias Nilsson CLK_MGT_ENTRY(SLIMCLK), 4243df57bcfSMattias Nilsson CLK_MGT_ENTRY(PER1CLK), 4253df57bcfSMattias Nilsson CLK_MGT_ENTRY(PER2CLK), 4263df57bcfSMattias Nilsson CLK_MGT_ENTRY(PER3CLK), 4273df57bcfSMattias Nilsson CLK_MGT_ENTRY(PER5CLK), 4283df57bcfSMattias Nilsson CLK_MGT_ENTRY(PER6CLK), 4293df57bcfSMattias Nilsson CLK_MGT_ENTRY(PER7CLK), 4303df57bcfSMattias Nilsson CLK_MGT_ENTRY(LCDCLK), 4313df57bcfSMattias Nilsson CLK_MGT_ENTRY(BMLCLK), 4323df57bcfSMattias Nilsson CLK_MGT_ENTRY(HSITXCLK), 4333df57bcfSMattias Nilsson CLK_MGT_ENTRY(HSIRXCLK), 4343df57bcfSMattias Nilsson CLK_MGT_ENTRY(HDMICLK), 4353df57bcfSMattias Nilsson CLK_MGT_ENTRY(APEATCLK), 4363df57bcfSMattias Nilsson CLK_MGT_ENTRY(APETRACECLK), 4373df57bcfSMattias Nilsson CLK_MGT_ENTRY(MCDECLK), 4383df57bcfSMattias Nilsson CLK_MGT_ENTRY(IPI2CCLK), 4393df57bcfSMattias Nilsson CLK_MGT_ENTRY(DSIALTCLK), 4403df57bcfSMattias Nilsson CLK_MGT_ENTRY(DMACLK), 4413df57bcfSMattias Nilsson CLK_MGT_ENTRY(B2R2CLK), 4423df57bcfSMattias Nilsson CLK_MGT_ENTRY(TVCLK), 4433df57bcfSMattias Nilsson CLK_MGT_ENTRY(SSPCLK), 4443df57bcfSMattias Nilsson CLK_MGT_ENTRY(RNGCLK), 4453df57bcfSMattias Nilsson CLK_MGT_ENTRY(UICCCLK), 4463df57bcfSMattias Nilsson }; 4473df57bcfSMattias Nilsson 4483df57bcfSMattias Nilsson /* 4493df57bcfSMattias Nilsson * Used by MCDE to setup all necessary PRCMU registers 4503df57bcfSMattias Nilsson */ 4513df57bcfSMattias Nilsson #define PRCMU_RESET_DSIPLL 0x00004000 4523df57bcfSMattias Nilsson #define PRCMU_UNCLAMP_DSIPLL 0x00400800 4533df57bcfSMattias Nilsson 4543df57bcfSMattias Nilsson #define PRCMU_CLK_PLL_DIV_SHIFT 0 4553df57bcfSMattias Nilsson #define PRCMU_CLK_PLL_SW_SHIFT 5 4563df57bcfSMattias Nilsson #define PRCMU_CLK_38 (1 << 9) 4573df57bcfSMattias Nilsson #define PRCMU_CLK_38_SRC (1 << 10) 4583df57bcfSMattias Nilsson #define PRCMU_CLK_38_DIV (1 << 11) 4593df57bcfSMattias Nilsson 4603df57bcfSMattias Nilsson /* PLLDIV=12, PLLSW=4 (PLLDDR) */ 4613df57bcfSMattias Nilsson #define PRCMU_DSI_CLOCK_SETTING 0x0000008C 4623df57bcfSMattias Nilsson 4633df57bcfSMattias Nilsson /* PLLDIV=8, PLLSW=4 (PLLDDR) */ 4643df57bcfSMattias Nilsson #define PRCMU_DSI_CLOCK_SETTING_U8400 0x00000088 4653df57bcfSMattias Nilsson 4663df57bcfSMattias Nilsson /* DPI 50000000 Hz */ 4673df57bcfSMattias Nilsson #define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \ 4683df57bcfSMattias Nilsson (16 << PRCMU_CLK_PLL_DIV_SHIFT)) 4693df57bcfSMattias Nilsson #define PRCMU_DSI_LP_CLOCK_SETTING 0x00000E00 4703df57bcfSMattias Nilsson 4713df57bcfSMattias Nilsson /* D=101, N=1, R=4, SELDIV2=0 */ 4723df57bcfSMattias Nilsson #define PRCMU_PLLDSI_FREQ_SETTING 0x00040165 4733df57bcfSMattias Nilsson 4743df57bcfSMattias Nilsson /* D=70, N=1, R=3, SELDIV2=0 */ 4753df57bcfSMattias Nilsson #define PRCMU_PLLDSI_FREQ_SETTING_U8400 0x00030146 4763df57bcfSMattias Nilsson 4773df57bcfSMattias Nilsson #define PRCMU_ENABLE_PLLDSI 0x00000001 4783df57bcfSMattias Nilsson #define PRCMU_DISABLE_PLLDSI 0x00000000 4793df57bcfSMattias Nilsson #define PRCMU_RELEASE_RESET_DSS 0x0000400C 4803df57bcfSMattias Nilsson #define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202 4813df57bcfSMattias Nilsson /* ESC clk, div0=1, div1=1, div2=3 */ 4823df57bcfSMattias Nilsson #define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x07030101 4833df57bcfSMattias Nilsson #define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101 4843df57bcfSMattias Nilsson #define PRCMU_DSI_RESET_SW 0x00000007 4853df57bcfSMattias Nilsson 4863df57bcfSMattias Nilsson #define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 4873df57bcfSMattias Nilsson 4883df57bcfSMattias Nilsson static struct { 4893df57bcfSMattias Nilsson u8 project_number; 4903df57bcfSMattias Nilsson u8 api_version; 4913df57bcfSMattias Nilsson u8 func_version; 4923df57bcfSMattias Nilsson u8 errata; 4933df57bcfSMattias Nilsson } prcmu_version; 4943df57bcfSMattias Nilsson 4953df57bcfSMattias Nilsson 4963df57bcfSMattias Nilsson int prcmu_enable_dsipll(void) 4973df57bcfSMattias Nilsson { 4983df57bcfSMattias Nilsson int i; 4993df57bcfSMattias Nilsson unsigned int plldsifreq; 5003df57bcfSMattias Nilsson 5013df57bcfSMattias Nilsson /* Clear DSIPLL_RESETN */ 5023df57bcfSMattias Nilsson writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_CLR)); 5033df57bcfSMattias Nilsson /* Unclamp DSIPLL in/out */ 5043df57bcfSMattias Nilsson writel(PRCMU_UNCLAMP_DSIPLL, (_PRCMU_BASE + PRCM_MMIP_LS_CLAMP_CLR)); 5053df57bcfSMattias Nilsson 5063df57bcfSMattias Nilsson if (prcmu_is_u8400()) 5073df57bcfSMattias Nilsson plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400; 5083df57bcfSMattias Nilsson else 5093df57bcfSMattias Nilsson plldsifreq = PRCMU_PLLDSI_FREQ_SETTING; 5103df57bcfSMattias Nilsson /* Set DSI PLL FREQ */ 5113df57bcfSMattias Nilsson writel(plldsifreq, (_PRCMU_BASE + PRCM_PLLDSI_FREQ)); 5123df57bcfSMattias Nilsson writel(PRCMU_DSI_PLLOUT_SEL_SETTING, 5133df57bcfSMattias Nilsson (_PRCMU_BASE + PRCM_DSI_PLLOUT_SEL)); 5143df57bcfSMattias Nilsson /* Enable Escape clocks */ 5153df57bcfSMattias Nilsson writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, 5163df57bcfSMattias Nilsson (_PRCMU_BASE + PRCM_DSITVCLK_DIV)); 5173df57bcfSMattias Nilsson 5183df57bcfSMattias Nilsson /* Start DSI PLL */ 5193df57bcfSMattias Nilsson writel(PRCMU_ENABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE)); 5203df57bcfSMattias Nilsson /* Reset DSI PLL */ 5213df57bcfSMattias Nilsson writel(PRCMU_DSI_RESET_SW, (_PRCMU_BASE + PRCM_DSI_SW_RESET)); 5223df57bcfSMattias Nilsson for (i = 0; i < 10; i++) { 5233df57bcfSMattias Nilsson if ((readl(_PRCMU_BASE + PRCM_PLLDSI_LOCKP) & 5243df57bcfSMattias Nilsson PRCMU_PLLDSI_LOCKP_LOCKED) 5253df57bcfSMattias Nilsson == PRCMU_PLLDSI_LOCKP_LOCKED) 5263df57bcfSMattias Nilsson break; 5273df57bcfSMattias Nilsson udelay(100); 5283df57bcfSMattias Nilsson } 5293df57bcfSMattias Nilsson /* Set DSIPLL_RESETN */ 5303df57bcfSMattias Nilsson writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_SET)); 5313df57bcfSMattias Nilsson return 0; 5323df57bcfSMattias Nilsson } 5333df57bcfSMattias Nilsson 5343df57bcfSMattias Nilsson int prcmu_disable_dsipll(void) 5353df57bcfSMattias Nilsson { 5363df57bcfSMattias Nilsson /* Disable dsi pll */ 5373df57bcfSMattias Nilsson writel(PRCMU_DISABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE)); 5383df57bcfSMattias Nilsson /* Disable escapeclock */ 5393df57bcfSMattias Nilsson writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, 5403df57bcfSMattias Nilsson (_PRCMU_BASE + PRCM_DSITVCLK_DIV)); 5413df57bcfSMattias Nilsson return 0; 5423df57bcfSMattias Nilsson } 5433df57bcfSMattias Nilsson 5443df57bcfSMattias Nilsson int prcmu_set_display_clocks(void) 5453df57bcfSMattias Nilsson { 5463df57bcfSMattias Nilsson unsigned long flags; 5473df57bcfSMattias Nilsson unsigned int dsiclk; 5483df57bcfSMattias Nilsson 5493df57bcfSMattias Nilsson if (prcmu_is_u8400()) 5503df57bcfSMattias Nilsson dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400; 5513df57bcfSMattias Nilsson else 5523df57bcfSMattias Nilsson dsiclk = PRCMU_DSI_CLOCK_SETTING; 5533df57bcfSMattias Nilsson 5543df57bcfSMattias Nilsson spin_lock_irqsave(&clk_mgt_lock, flags); 5553df57bcfSMattias Nilsson 5563df57bcfSMattias Nilsson /* Grab the HW semaphore. */ 5573df57bcfSMattias Nilsson while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) 5583df57bcfSMattias Nilsson cpu_relax(); 5593df57bcfSMattias Nilsson 5603df57bcfSMattias Nilsson writel(dsiclk, (_PRCMU_BASE + PRCM_HDMICLK_MGT)); 5613df57bcfSMattias Nilsson writel(PRCMU_DSI_LP_CLOCK_SETTING, (_PRCMU_BASE + PRCM_TVCLK_MGT)); 5623df57bcfSMattias Nilsson writel(PRCMU_DPI_CLOCK_SETTING, (_PRCMU_BASE + PRCM_LCDCLK_MGT)); 5633df57bcfSMattias Nilsson 5643df57bcfSMattias Nilsson /* Release the HW semaphore. */ 5653df57bcfSMattias Nilsson writel(0, (_PRCMU_BASE + PRCM_SEM)); 5663df57bcfSMattias Nilsson 5673df57bcfSMattias Nilsson spin_unlock_irqrestore(&clk_mgt_lock, flags); 5683df57bcfSMattias Nilsson 5693df57bcfSMattias Nilsson return 0; 5703df57bcfSMattias Nilsson } 5713df57bcfSMattias Nilsson 5723df57bcfSMattias Nilsson /** 5733df57bcfSMattias Nilsson * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1. 5743df57bcfSMattias Nilsson */ 5753df57bcfSMattias Nilsson void prcmu_enable_spi2(void) 5763df57bcfSMattias Nilsson { 5773df57bcfSMattias Nilsson u32 reg; 5783df57bcfSMattias Nilsson unsigned long flags; 5793df57bcfSMattias Nilsson 5803df57bcfSMattias Nilsson spin_lock_irqsave(&gpiocr_lock, flags); 5813df57bcfSMattias Nilsson reg = readl(_PRCMU_BASE + PRCM_GPIOCR); 5823df57bcfSMattias Nilsson writel(reg | PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR); 5833df57bcfSMattias Nilsson spin_unlock_irqrestore(&gpiocr_lock, flags); 5843df57bcfSMattias Nilsson } 5853df57bcfSMattias Nilsson 5863df57bcfSMattias Nilsson /** 5873df57bcfSMattias Nilsson * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1. 5883df57bcfSMattias Nilsson */ 5893df57bcfSMattias Nilsson void prcmu_disable_spi2(void) 5903df57bcfSMattias Nilsson { 5913df57bcfSMattias Nilsson u32 reg; 5923df57bcfSMattias Nilsson unsigned long flags; 5933df57bcfSMattias Nilsson 5943df57bcfSMattias Nilsson spin_lock_irqsave(&gpiocr_lock, flags); 5953df57bcfSMattias Nilsson reg = readl(_PRCMU_BASE + PRCM_GPIOCR); 5963df57bcfSMattias Nilsson writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR); 5973df57bcfSMattias Nilsson spin_unlock_irqrestore(&gpiocr_lock, flags); 5983df57bcfSMattias Nilsson } 5993df57bcfSMattias Nilsson 6003df57bcfSMattias Nilsson bool prcmu_has_arm_maxopp(void) 6013df57bcfSMattias Nilsson { 6023df57bcfSMattias Nilsson return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) & 6033df57bcfSMattias Nilsson PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK; 6043df57bcfSMattias Nilsson } 6053df57bcfSMattias Nilsson 6063df57bcfSMattias Nilsson bool prcmu_is_u8400(void) 6073df57bcfSMattias Nilsson { 6083df57bcfSMattias Nilsson return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0; 6093df57bcfSMattias Nilsson } 6103df57bcfSMattias Nilsson 6113df57bcfSMattias Nilsson /** 6123df57bcfSMattias Nilsson * prcmu_get_boot_status - PRCMU boot status checking 6133df57bcfSMattias Nilsson * Returns: the current PRCMU boot status 6143df57bcfSMattias Nilsson */ 6153df57bcfSMattias Nilsson int prcmu_get_boot_status(void) 6163df57bcfSMattias Nilsson { 6173df57bcfSMattias Nilsson return readb(tcdm_base + PRCM_BOOT_STATUS); 6183df57bcfSMattias Nilsson } 6193df57bcfSMattias Nilsson 6203df57bcfSMattias Nilsson /** 6213df57bcfSMattias Nilsson * prcmu_set_rc_a2p - This function is used to run few power state sequences 6223df57bcfSMattias Nilsson * @val: Value to be set, i.e. transition requested 6233df57bcfSMattias Nilsson * Returns: 0 on success, -EINVAL on invalid argument 6243df57bcfSMattias Nilsson * 6253df57bcfSMattias Nilsson * This function is used to run the following power state sequences - 6263df57bcfSMattias Nilsson * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep 6273df57bcfSMattias Nilsson */ 6283df57bcfSMattias Nilsson int prcmu_set_rc_a2p(enum romcode_write val) 6293df57bcfSMattias Nilsson { 6303df57bcfSMattias Nilsson if (val < RDY_2_DS || val > RDY_2_XP70_RST) 6313df57bcfSMattias Nilsson return -EINVAL; 6323df57bcfSMattias Nilsson writeb(val, (tcdm_base + PRCM_ROMCODE_A2P)); 6333df57bcfSMattias Nilsson return 0; 6343df57bcfSMattias Nilsson } 6353df57bcfSMattias Nilsson 6363df57bcfSMattias Nilsson /** 6373df57bcfSMattias Nilsson * prcmu_get_rc_p2a - This function is used to get power state sequences 6383df57bcfSMattias Nilsson * Returns: the power transition that has last happened 6393df57bcfSMattias Nilsson * 6403df57bcfSMattias Nilsson * This function can return the following transitions- 6413df57bcfSMattias Nilsson * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep 6423df57bcfSMattias Nilsson */ 6433df57bcfSMattias Nilsson enum romcode_read prcmu_get_rc_p2a(void) 6443df57bcfSMattias Nilsson { 6453df57bcfSMattias Nilsson return readb(tcdm_base + PRCM_ROMCODE_P2A); 6463df57bcfSMattias Nilsson } 6473df57bcfSMattias Nilsson 6483df57bcfSMattias Nilsson /** 6493df57bcfSMattias Nilsson * prcmu_get_current_mode - Return the current XP70 power mode 6503df57bcfSMattias Nilsson * Returns: Returns the current AP(ARM) power mode: init, 6513df57bcfSMattias Nilsson * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset 6523df57bcfSMattias Nilsson */ 6533df57bcfSMattias Nilsson enum ap_pwrst prcmu_get_xp70_current_state(void) 6543df57bcfSMattias Nilsson { 6553df57bcfSMattias Nilsson return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE); 6563df57bcfSMattias Nilsson } 6573df57bcfSMattias Nilsson 6583df57bcfSMattias Nilsson /** 6593df57bcfSMattias Nilsson * prcmu_config_clkout - Configure one of the programmable clock outputs. 6603df57bcfSMattias Nilsson * @clkout: The CLKOUT number (0 or 1). 6613df57bcfSMattias Nilsson * @source: The clock to be used (one of the PRCMU_CLKSRC_*). 6623df57bcfSMattias Nilsson * @div: The divider to be applied. 6633df57bcfSMattias Nilsson * 6643df57bcfSMattias Nilsson * Configures one of the programmable clock outputs (CLKOUTs). 6653df57bcfSMattias Nilsson * @div should be in the range [1,63] to request a configuration, or 0 to 6663df57bcfSMattias Nilsson * inform that the configuration is no longer requested. 6673df57bcfSMattias Nilsson */ 6683df57bcfSMattias Nilsson int prcmu_config_clkout(u8 clkout, u8 source, u8 div) 6693df57bcfSMattias Nilsson { 6703df57bcfSMattias Nilsson static int requests[2]; 6713df57bcfSMattias Nilsson int r = 0; 6723df57bcfSMattias Nilsson unsigned long flags; 6733df57bcfSMattias Nilsson u32 val; 6743df57bcfSMattias Nilsson u32 bits; 6753df57bcfSMattias Nilsson u32 mask; 6763df57bcfSMattias Nilsson u32 div_mask; 6773df57bcfSMattias Nilsson 6783df57bcfSMattias Nilsson BUG_ON(clkout > 1); 6793df57bcfSMattias Nilsson BUG_ON(div > 63); 6803df57bcfSMattias Nilsson BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009)); 6813df57bcfSMattias Nilsson 6823df57bcfSMattias Nilsson if (!div && !requests[clkout]) 6833df57bcfSMattias Nilsson return -EINVAL; 6843df57bcfSMattias Nilsson 6853df57bcfSMattias Nilsson switch (clkout) { 6863df57bcfSMattias Nilsson case 0: 6873df57bcfSMattias Nilsson div_mask = PRCM_CLKOCR_CLKODIV0_MASK; 6883df57bcfSMattias Nilsson mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK); 6893df57bcfSMattias Nilsson bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) | 6903df57bcfSMattias Nilsson (div << PRCM_CLKOCR_CLKODIV0_SHIFT)); 6913df57bcfSMattias Nilsson break; 6923df57bcfSMattias Nilsson case 1: 6933df57bcfSMattias Nilsson div_mask = PRCM_CLKOCR_CLKODIV1_MASK; 6943df57bcfSMattias Nilsson mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK | 6953df57bcfSMattias Nilsson PRCM_CLKOCR_CLK1TYPE); 6963df57bcfSMattias Nilsson bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) | 6973df57bcfSMattias Nilsson (div << PRCM_CLKOCR_CLKODIV1_SHIFT)); 6983df57bcfSMattias Nilsson break; 6993df57bcfSMattias Nilsson } 7003df57bcfSMattias Nilsson bits &= mask; 7013df57bcfSMattias Nilsson 7023df57bcfSMattias Nilsson spin_lock_irqsave(&clkout_lock, flags); 7033df57bcfSMattias Nilsson 7043df57bcfSMattias Nilsson val = readl(_PRCMU_BASE + PRCM_CLKOCR); 7053df57bcfSMattias Nilsson if (val & div_mask) { 7063df57bcfSMattias Nilsson if (div) { 7073df57bcfSMattias Nilsson if ((val & mask) != bits) { 7083df57bcfSMattias Nilsson r = -EBUSY; 7093df57bcfSMattias Nilsson goto unlock_and_return; 7103df57bcfSMattias Nilsson } 7113df57bcfSMattias Nilsson } else { 7123df57bcfSMattias Nilsson if ((val & mask & ~div_mask) != bits) { 7133df57bcfSMattias Nilsson r = -EINVAL; 7143df57bcfSMattias Nilsson goto unlock_and_return; 7153df57bcfSMattias Nilsson } 7163df57bcfSMattias Nilsson } 7173df57bcfSMattias Nilsson } 7183df57bcfSMattias Nilsson writel((bits | (val & ~mask)), (_PRCMU_BASE + PRCM_CLKOCR)); 7193df57bcfSMattias Nilsson requests[clkout] += (div ? 1 : -1); 7203df57bcfSMattias Nilsson 7213df57bcfSMattias Nilsson unlock_and_return: 7223df57bcfSMattias Nilsson spin_unlock_irqrestore(&clkout_lock, flags); 7233df57bcfSMattias Nilsson 7243df57bcfSMattias Nilsson return r; 7253df57bcfSMattias Nilsson } 7263df57bcfSMattias Nilsson 7273df57bcfSMattias Nilsson int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll) 7283df57bcfSMattias Nilsson { 7293df57bcfSMattias Nilsson unsigned long flags; 7303df57bcfSMattias Nilsson 7313df57bcfSMattias Nilsson BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state)); 7323df57bcfSMattias Nilsson 7333df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.lock, flags); 7343df57bcfSMattias Nilsson 7353df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) 7363df57bcfSMattias Nilsson cpu_relax(); 7373df57bcfSMattias Nilsson 7383df57bcfSMattias Nilsson writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); 7393df57bcfSMattias Nilsson writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE)); 7403df57bcfSMattias Nilsson writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE)); 7413df57bcfSMattias Nilsson writeb((keep_ulp_clk ? 1 : 0), 7423df57bcfSMattias Nilsson (tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE)); 7433df57bcfSMattias Nilsson writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI)); 7443df57bcfSMattias Nilsson writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 7453df57bcfSMattias Nilsson 7463df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.lock, flags); 7473df57bcfSMattias Nilsson 7483df57bcfSMattias Nilsson return 0; 7493df57bcfSMattias Nilsson } 7503df57bcfSMattias Nilsson 7513df57bcfSMattias Nilsson /* This function should only be called while mb0_transfer.lock is held. */ 7523df57bcfSMattias Nilsson static void config_wakeups(void) 7533df57bcfSMattias Nilsson { 7543df57bcfSMattias Nilsson const u8 header[2] = { 7553df57bcfSMattias Nilsson MB0H_CONFIG_WAKEUPS_EXE, 7563df57bcfSMattias Nilsson MB0H_CONFIG_WAKEUPS_SLEEP 7573df57bcfSMattias Nilsson }; 7583df57bcfSMattias Nilsson static u32 last_dbb_events; 7593df57bcfSMattias Nilsson static u32 last_abb_events; 7603df57bcfSMattias Nilsson u32 dbb_events; 7613df57bcfSMattias Nilsson u32 abb_events; 7623df57bcfSMattias Nilsson unsigned int i; 7633df57bcfSMattias Nilsson 7643df57bcfSMattias Nilsson dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups; 7653df57bcfSMattias Nilsson dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK); 7663df57bcfSMattias Nilsson 7673df57bcfSMattias Nilsson abb_events = mb0_transfer.req.abb_events; 7683df57bcfSMattias Nilsson 7693df57bcfSMattias Nilsson if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events)) 7703df57bcfSMattias Nilsson return; 7713df57bcfSMattias Nilsson 7723df57bcfSMattias Nilsson for (i = 0; i < 2; i++) { 7733df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) 7743df57bcfSMattias Nilsson cpu_relax(); 7753df57bcfSMattias Nilsson writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500)); 7763df57bcfSMattias Nilsson writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500)); 7773df57bcfSMattias Nilsson writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); 7783df57bcfSMattias Nilsson writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 7793df57bcfSMattias Nilsson } 7803df57bcfSMattias Nilsson last_dbb_events = dbb_events; 7813df57bcfSMattias Nilsson last_abb_events = abb_events; 7823df57bcfSMattias Nilsson } 7833df57bcfSMattias Nilsson 7843df57bcfSMattias Nilsson void prcmu_enable_wakeups(u32 wakeups) 7853df57bcfSMattias Nilsson { 7863df57bcfSMattias Nilsson unsigned long flags; 7873df57bcfSMattias Nilsson u32 bits; 7883df57bcfSMattias Nilsson int i; 7893df57bcfSMattias Nilsson 7903df57bcfSMattias Nilsson BUG_ON(wakeups != (wakeups & VALID_WAKEUPS)); 7913df57bcfSMattias Nilsson 7923df57bcfSMattias Nilsson for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) { 7933df57bcfSMattias Nilsson if (wakeups & BIT(i)) 7943df57bcfSMattias Nilsson bits |= prcmu_wakeup_bit[i]; 7953df57bcfSMattias Nilsson } 7963df57bcfSMattias Nilsson 7973df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.lock, flags); 7983df57bcfSMattias Nilsson 7993df57bcfSMattias Nilsson mb0_transfer.req.dbb_wakeups = bits; 8003df57bcfSMattias Nilsson config_wakeups(); 8013df57bcfSMattias Nilsson 8023df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.lock, flags); 8033df57bcfSMattias Nilsson } 8043df57bcfSMattias Nilsson 8053df57bcfSMattias Nilsson void prcmu_config_abb_event_readout(u32 abb_events) 8063df57bcfSMattias Nilsson { 8073df57bcfSMattias Nilsson unsigned long flags; 8083df57bcfSMattias Nilsson 8093df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.lock, flags); 8103df57bcfSMattias Nilsson 8113df57bcfSMattias Nilsson mb0_transfer.req.abb_events = abb_events; 8123df57bcfSMattias Nilsson config_wakeups(); 8133df57bcfSMattias Nilsson 8143df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.lock, flags); 8153df57bcfSMattias Nilsson } 8163df57bcfSMattias Nilsson 8173df57bcfSMattias Nilsson void prcmu_get_abb_event_buffer(void __iomem **buf) 8183df57bcfSMattias Nilsson { 8193df57bcfSMattias Nilsson if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) 8203df57bcfSMattias Nilsson *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500); 8213df57bcfSMattias Nilsson else 8223df57bcfSMattias Nilsson *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500); 8233df57bcfSMattias Nilsson } 8243df57bcfSMattias Nilsson 8253df57bcfSMattias Nilsson /** 8263df57bcfSMattias Nilsson * prcmu_set_arm_opp - set the appropriate ARM OPP 8273df57bcfSMattias Nilsson * @opp: The new ARM operating point to which transition is to be made 8283df57bcfSMattias Nilsson * Returns: 0 on success, non-zero on failure 8293df57bcfSMattias Nilsson * 8303df57bcfSMattias Nilsson * This function sets the the operating point of the ARM. 8313df57bcfSMattias Nilsson */ 8323df57bcfSMattias Nilsson int prcmu_set_arm_opp(u8 opp) 8333df57bcfSMattias Nilsson { 8343df57bcfSMattias Nilsson int r; 8353df57bcfSMattias Nilsson 8363df57bcfSMattias Nilsson if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK) 8373df57bcfSMattias Nilsson return -EINVAL; 8383df57bcfSMattias Nilsson 8393df57bcfSMattias Nilsson r = 0; 8403df57bcfSMattias Nilsson 8413df57bcfSMattias Nilsson mutex_lock(&mb1_transfer.lock); 8423df57bcfSMattias Nilsson 8433df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) 8443df57bcfSMattias Nilsson cpu_relax(); 8453df57bcfSMattias Nilsson 8463df57bcfSMattias Nilsson writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); 8473df57bcfSMattias Nilsson writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP)); 8483df57bcfSMattias Nilsson writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP)); 8493df57bcfSMattias Nilsson 8503df57bcfSMattias Nilsson writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 8513df57bcfSMattias Nilsson wait_for_completion(&mb1_transfer.work); 8523df57bcfSMattias Nilsson 8533df57bcfSMattias Nilsson if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) || 8543df57bcfSMattias Nilsson (mb1_transfer.ack.arm_opp != opp)) 8553df57bcfSMattias Nilsson r = -EIO; 8563df57bcfSMattias Nilsson 8573df57bcfSMattias Nilsson mutex_unlock(&mb1_transfer.lock); 8583df57bcfSMattias Nilsson 8593df57bcfSMattias Nilsson return r; 8603df57bcfSMattias Nilsson } 8613df57bcfSMattias Nilsson 8623df57bcfSMattias Nilsson /** 8633df57bcfSMattias Nilsson * prcmu_get_arm_opp - get the current ARM OPP 8643df57bcfSMattias Nilsson * 8653df57bcfSMattias Nilsson * Returns: the current ARM OPP 8663df57bcfSMattias Nilsson */ 8673df57bcfSMattias Nilsson int prcmu_get_arm_opp(void) 8683df57bcfSMattias Nilsson { 8693df57bcfSMattias Nilsson return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP); 8703df57bcfSMattias Nilsson } 8713df57bcfSMattias Nilsson 8723df57bcfSMattias Nilsson /** 8733df57bcfSMattias Nilsson * prcmu_get_ddr_opp - get the current DDR OPP 8743df57bcfSMattias Nilsson * 8753df57bcfSMattias Nilsson * Returns: the current DDR OPP 8763df57bcfSMattias Nilsson */ 8773df57bcfSMattias Nilsson int prcmu_get_ddr_opp(void) 8783df57bcfSMattias Nilsson { 8793df57bcfSMattias Nilsson return readb(_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW); 8803df57bcfSMattias Nilsson } 8813df57bcfSMattias Nilsson 8823df57bcfSMattias Nilsson /** 8833df57bcfSMattias Nilsson * set_ddr_opp - set the appropriate DDR OPP 8843df57bcfSMattias Nilsson * @opp: The new DDR operating point to which transition is to be made 8853df57bcfSMattias Nilsson * Returns: 0 on success, non-zero on failure 8863df57bcfSMattias Nilsson * 8873df57bcfSMattias Nilsson * This function sets the operating point of the DDR. 8883df57bcfSMattias Nilsson */ 8893df57bcfSMattias Nilsson int prcmu_set_ddr_opp(u8 opp) 8903df57bcfSMattias Nilsson { 8913df57bcfSMattias Nilsson if (opp < DDR_100_OPP || opp > DDR_25_OPP) 8923df57bcfSMattias Nilsson return -EINVAL; 8933df57bcfSMattias Nilsson /* Changing the DDR OPP can hang the hardware pre-v21 */ 8943df57bcfSMattias Nilsson if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20()) 8953df57bcfSMattias Nilsson writeb(opp, (_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW)); 8963df57bcfSMattias Nilsson 8973df57bcfSMattias Nilsson return 0; 8983df57bcfSMattias Nilsson } 8993df57bcfSMattias Nilsson /** 9003df57bcfSMattias Nilsson * set_ape_opp - set the appropriate APE OPP 9013df57bcfSMattias Nilsson * @opp: The new APE operating point to which transition is to be made 9023df57bcfSMattias Nilsson * Returns: 0 on success, non-zero on failure 9033df57bcfSMattias Nilsson * 9043df57bcfSMattias Nilsson * This function sets the operating point of the APE. 9053df57bcfSMattias Nilsson */ 9063df57bcfSMattias Nilsson int prcmu_set_ape_opp(u8 opp) 9073df57bcfSMattias Nilsson { 9083df57bcfSMattias Nilsson int r = 0; 9093df57bcfSMattias Nilsson 9103df57bcfSMattias Nilsson mutex_lock(&mb1_transfer.lock); 9113df57bcfSMattias Nilsson 9123df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) 9133df57bcfSMattias Nilsson cpu_relax(); 9143df57bcfSMattias Nilsson 9153df57bcfSMattias Nilsson writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); 9163df57bcfSMattias Nilsson writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP)); 9173df57bcfSMattias Nilsson writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP)); 9183df57bcfSMattias Nilsson 9193df57bcfSMattias Nilsson writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 9203df57bcfSMattias Nilsson wait_for_completion(&mb1_transfer.work); 9213df57bcfSMattias Nilsson 9223df57bcfSMattias Nilsson if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) || 9233df57bcfSMattias Nilsson (mb1_transfer.ack.ape_opp != opp)) 9243df57bcfSMattias Nilsson r = -EIO; 9253df57bcfSMattias Nilsson 9263df57bcfSMattias Nilsson mutex_unlock(&mb1_transfer.lock); 9273df57bcfSMattias Nilsson 9283df57bcfSMattias Nilsson return r; 9293df57bcfSMattias Nilsson } 9303df57bcfSMattias Nilsson 9313df57bcfSMattias Nilsson /** 9323df57bcfSMattias Nilsson * prcmu_get_ape_opp - get the current APE OPP 9333df57bcfSMattias Nilsson * 9343df57bcfSMattias Nilsson * Returns: the current APE OPP 9353df57bcfSMattias Nilsson */ 9363df57bcfSMattias Nilsson int prcmu_get_ape_opp(void) 9373df57bcfSMattias Nilsson { 9383df57bcfSMattias Nilsson return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP); 9393df57bcfSMattias Nilsson } 9403df57bcfSMattias Nilsson 9413df57bcfSMattias Nilsson /** 9423df57bcfSMattias Nilsson * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage 9433df57bcfSMattias Nilsson * @enable: true to request the higher voltage, false to drop a request. 9443df57bcfSMattias Nilsson * 9453df57bcfSMattias Nilsson * Calls to this function to enable and disable requests must be balanced. 9463df57bcfSMattias Nilsson */ 9473df57bcfSMattias Nilsson int prcmu_request_ape_opp_100_voltage(bool enable) 9483df57bcfSMattias Nilsson { 9493df57bcfSMattias Nilsson int r = 0; 9503df57bcfSMattias Nilsson u8 header; 9513df57bcfSMattias Nilsson static unsigned int requests; 9523df57bcfSMattias Nilsson 9533df57bcfSMattias Nilsson mutex_lock(&mb1_transfer.lock); 9543df57bcfSMattias Nilsson 9553df57bcfSMattias Nilsson if (enable) { 9563df57bcfSMattias Nilsson if (0 != requests++) 9573df57bcfSMattias Nilsson goto unlock_and_return; 9583df57bcfSMattias Nilsson header = MB1H_REQUEST_APE_OPP_100_VOLT; 9593df57bcfSMattias Nilsson } else { 9603df57bcfSMattias Nilsson if (requests == 0) { 9613df57bcfSMattias Nilsson r = -EIO; 9623df57bcfSMattias Nilsson goto unlock_and_return; 9633df57bcfSMattias Nilsson } else if (1 != requests--) { 9643df57bcfSMattias Nilsson goto unlock_and_return; 9653df57bcfSMattias Nilsson } 9663df57bcfSMattias Nilsson header = MB1H_RELEASE_APE_OPP_100_VOLT; 9673df57bcfSMattias Nilsson } 9683df57bcfSMattias Nilsson 9693df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) 9703df57bcfSMattias Nilsson cpu_relax(); 9713df57bcfSMattias Nilsson 9723df57bcfSMattias Nilsson writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); 9733df57bcfSMattias Nilsson 9743df57bcfSMattias Nilsson writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 9753df57bcfSMattias Nilsson wait_for_completion(&mb1_transfer.work); 9763df57bcfSMattias Nilsson 9773df57bcfSMattias Nilsson if ((mb1_transfer.ack.header != header) || 9783df57bcfSMattias Nilsson ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0)) 9793df57bcfSMattias Nilsson r = -EIO; 9803df57bcfSMattias Nilsson 9813df57bcfSMattias Nilsson unlock_and_return: 9823df57bcfSMattias Nilsson mutex_unlock(&mb1_transfer.lock); 9833df57bcfSMattias Nilsson 9843df57bcfSMattias Nilsson return r; 9853df57bcfSMattias Nilsson } 9863df57bcfSMattias Nilsson 9873df57bcfSMattias Nilsson /** 9883df57bcfSMattias Nilsson * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup 9893df57bcfSMattias Nilsson * 9903df57bcfSMattias Nilsson * This function releases the power state requirements of a USB wakeup. 9913df57bcfSMattias Nilsson */ 9923df57bcfSMattias Nilsson int prcmu_release_usb_wakeup_state(void) 9933df57bcfSMattias Nilsson { 9943df57bcfSMattias Nilsson int r = 0; 9953df57bcfSMattias Nilsson 9963df57bcfSMattias Nilsson mutex_lock(&mb1_transfer.lock); 9973df57bcfSMattias Nilsson 9983df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) 9993df57bcfSMattias Nilsson cpu_relax(); 10003df57bcfSMattias Nilsson 10013df57bcfSMattias Nilsson writeb(MB1H_RELEASE_USB_WAKEUP, 10023df57bcfSMattias Nilsson (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); 10033df57bcfSMattias Nilsson 10043df57bcfSMattias Nilsson writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 10053df57bcfSMattias Nilsson wait_for_completion(&mb1_transfer.work); 10063df57bcfSMattias Nilsson 10073df57bcfSMattias Nilsson if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) || 10083df57bcfSMattias Nilsson ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0)) 10093df57bcfSMattias Nilsson r = -EIO; 10103df57bcfSMattias Nilsson 10113df57bcfSMattias Nilsson mutex_unlock(&mb1_transfer.lock); 10123df57bcfSMattias Nilsson 10133df57bcfSMattias Nilsson return r; 10143df57bcfSMattias Nilsson } 10153df57bcfSMattias Nilsson 10163df57bcfSMattias Nilsson /** 10173df57bcfSMattias Nilsson * prcmu_set_epod - set the state of a EPOD (power domain) 10183df57bcfSMattias Nilsson * @epod_id: The EPOD to set 10193df57bcfSMattias Nilsson * @epod_state: The new EPOD state 10203df57bcfSMattias Nilsson * 10213df57bcfSMattias Nilsson * This function sets the state of a EPOD (power domain). It may not be called 10223df57bcfSMattias Nilsson * from interrupt context. 10233df57bcfSMattias Nilsson */ 10243df57bcfSMattias Nilsson int prcmu_set_epod(u16 epod_id, u8 epod_state) 10253df57bcfSMattias Nilsson { 10263df57bcfSMattias Nilsson int r = 0; 10273df57bcfSMattias Nilsson bool ram_retention = false; 10283df57bcfSMattias Nilsson int i; 10293df57bcfSMattias Nilsson 10303df57bcfSMattias Nilsson /* check argument */ 10313df57bcfSMattias Nilsson BUG_ON(epod_id >= NUM_EPOD_ID); 10323df57bcfSMattias Nilsson 10333df57bcfSMattias Nilsson /* set flag if retention is possible */ 10343df57bcfSMattias Nilsson switch (epod_id) { 10353df57bcfSMattias Nilsson case EPOD_ID_SVAMMDSP: 10363df57bcfSMattias Nilsson case EPOD_ID_SIAMMDSP: 10373df57bcfSMattias Nilsson case EPOD_ID_ESRAM12: 10383df57bcfSMattias Nilsson case EPOD_ID_ESRAM34: 10393df57bcfSMattias Nilsson ram_retention = true; 10403df57bcfSMattias Nilsson break; 10413df57bcfSMattias Nilsson } 10423df57bcfSMattias Nilsson 10433df57bcfSMattias Nilsson /* check argument */ 10443df57bcfSMattias Nilsson BUG_ON(epod_state > EPOD_STATE_ON); 10453df57bcfSMattias Nilsson BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention); 10463df57bcfSMattias Nilsson 10473df57bcfSMattias Nilsson /* get lock */ 10483df57bcfSMattias Nilsson mutex_lock(&mb2_transfer.lock); 10493df57bcfSMattias Nilsson 10503df57bcfSMattias Nilsson /* wait for mailbox */ 10513df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2)) 10523df57bcfSMattias Nilsson cpu_relax(); 10533df57bcfSMattias Nilsson 10543df57bcfSMattias Nilsson /* fill in mailbox */ 10553df57bcfSMattias Nilsson for (i = 0; i < NUM_EPOD_ID; i++) 10563df57bcfSMattias Nilsson writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i)); 10573df57bcfSMattias Nilsson writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id)); 10583df57bcfSMattias Nilsson 10593df57bcfSMattias Nilsson writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2)); 10603df57bcfSMattias Nilsson 10613df57bcfSMattias Nilsson writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 10623df57bcfSMattias Nilsson 10633df57bcfSMattias Nilsson /* 10643df57bcfSMattias Nilsson * The current firmware version does not handle errors correctly, 10653df57bcfSMattias Nilsson * and we cannot recover if there is an error. 10663df57bcfSMattias Nilsson * This is expected to change when the firmware is updated. 10673df57bcfSMattias Nilsson */ 10683df57bcfSMattias Nilsson if (!wait_for_completion_timeout(&mb2_transfer.work, 10693df57bcfSMattias Nilsson msecs_to_jiffies(20000))) { 10703df57bcfSMattias Nilsson pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", 10713df57bcfSMattias Nilsson __func__); 10723df57bcfSMattias Nilsson r = -EIO; 10733df57bcfSMattias Nilsson goto unlock_and_return; 10743df57bcfSMattias Nilsson } 10753df57bcfSMattias Nilsson 10763df57bcfSMattias Nilsson if (mb2_transfer.ack.status != HWACC_PWR_ST_OK) 10773df57bcfSMattias Nilsson r = -EIO; 10783df57bcfSMattias Nilsson 10793df57bcfSMattias Nilsson unlock_and_return: 10803df57bcfSMattias Nilsson mutex_unlock(&mb2_transfer.lock); 10813df57bcfSMattias Nilsson return r; 10823df57bcfSMattias Nilsson } 10833df57bcfSMattias Nilsson 10843df57bcfSMattias Nilsson /** 10853df57bcfSMattias Nilsson * prcmu_configure_auto_pm - Configure autonomous power management. 10863df57bcfSMattias Nilsson * @sleep: Configuration for ApSleep. 10873df57bcfSMattias Nilsson * @idle: Configuration for ApIdle. 10883df57bcfSMattias Nilsson */ 10893df57bcfSMattias Nilsson void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep, 10903df57bcfSMattias Nilsson struct prcmu_auto_pm_config *idle) 10913df57bcfSMattias Nilsson { 10923df57bcfSMattias Nilsson u32 sleep_cfg; 10933df57bcfSMattias Nilsson u32 idle_cfg; 10943df57bcfSMattias Nilsson unsigned long flags; 10953df57bcfSMattias Nilsson 10963df57bcfSMattias Nilsson BUG_ON((sleep == NULL) || (idle == NULL)); 10973df57bcfSMattias Nilsson 10983df57bcfSMattias Nilsson sleep_cfg = (sleep->sva_auto_pm_enable & 0xF); 10993df57bcfSMattias Nilsson sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF)); 11003df57bcfSMattias Nilsson sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF)); 11013df57bcfSMattias Nilsson sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF)); 11023df57bcfSMattias Nilsson sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF)); 11033df57bcfSMattias Nilsson sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF)); 11043df57bcfSMattias Nilsson 11053df57bcfSMattias Nilsson idle_cfg = (idle->sva_auto_pm_enable & 0xF); 11063df57bcfSMattias Nilsson idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF)); 11073df57bcfSMattias Nilsson idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF)); 11083df57bcfSMattias Nilsson idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF)); 11093df57bcfSMattias Nilsson idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF)); 11103df57bcfSMattias Nilsson idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF)); 11113df57bcfSMattias Nilsson 11123df57bcfSMattias Nilsson spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags); 11133df57bcfSMattias Nilsson 11143df57bcfSMattias Nilsson /* 11153df57bcfSMattias Nilsson * The autonomous power management configuration is done through 11163df57bcfSMattias Nilsson * fields in mailbox 2, but these fields are only used as shared 11173df57bcfSMattias Nilsson * variables - i.e. there is no need to send a message. 11183df57bcfSMattias Nilsson */ 11193df57bcfSMattias Nilsson writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP)); 11203df57bcfSMattias Nilsson writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE)); 11213df57bcfSMattias Nilsson 11223df57bcfSMattias Nilsson mb2_transfer.auto_pm_enabled = 11233df57bcfSMattias Nilsson ((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) || 11243df57bcfSMattias Nilsson (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) || 11253df57bcfSMattias Nilsson (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) || 11263df57bcfSMattias Nilsson (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON)); 11273df57bcfSMattias Nilsson 11283df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags); 11293df57bcfSMattias Nilsson } 11303df57bcfSMattias Nilsson EXPORT_SYMBOL(prcmu_configure_auto_pm); 11313df57bcfSMattias Nilsson 11323df57bcfSMattias Nilsson bool prcmu_is_auto_pm_enabled(void) 11333df57bcfSMattias Nilsson { 11343df57bcfSMattias Nilsson return mb2_transfer.auto_pm_enabled; 11353df57bcfSMattias Nilsson } 11363df57bcfSMattias Nilsson 11373df57bcfSMattias Nilsson static int request_sysclk(bool enable) 11383df57bcfSMattias Nilsson { 11393df57bcfSMattias Nilsson int r; 11403df57bcfSMattias Nilsson unsigned long flags; 11413df57bcfSMattias Nilsson 11423df57bcfSMattias Nilsson r = 0; 11433df57bcfSMattias Nilsson 11443df57bcfSMattias Nilsson mutex_lock(&mb3_transfer.sysclk_lock); 11453df57bcfSMattias Nilsson 11463df57bcfSMattias Nilsson spin_lock_irqsave(&mb3_transfer.lock, flags); 11473df57bcfSMattias Nilsson 11483df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(3)) 11493df57bcfSMattias Nilsson cpu_relax(); 11503df57bcfSMattias Nilsson 11513df57bcfSMattias Nilsson writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT)); 11523df57bcfSMattias Nilsson 11533df57bcfSMattias Nilsson writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3)); 11543df57bcfSMattias Nilsson writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 11553df57bcfSMattias Nilsson 11563df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb3_transfer.lock, flags); 11573df57bcfSMattias Nilsson 11583df57bcfSMattias Nilsson /* 11593df57bcfSMattias Nilsson * The firmware only sends an ACK if we want to enable the 11603df57bcfSMattias Nilsson * SysClk, and it succeeds. 11613df57bcfSMattias Nilsson */ 11623df57bcfSMattias Nilsson if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work, 11633df57bcfSMattias Nilsson msecs_to_jiffies(20000))) { 11643df57bcfSMattias Nilsson pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", 11653df57bcfSMattias Nilsson __func__); 11663df57bcfSMattias Nilsson r = -EIO; 11673df57bcfSMattias Nilsson } 11683df57bcfSMattias Nilsson 11693df57bcfSMattias Nilsson mutex_unlock(&mb3_transfer.sysclk_lock); 11703df57bcfSMattias Nilsson 11713df57bcfSMattias Nilsson return r; 11723df57bcfSMattias Nilsson } 11733df57bcfSMattias Nilsson 11743df57bcfSMattias Nilsson static int request_timclk(bool enable) 11753df57bcfSMattias Nilsson { 11763df57bcfSMattias Nilsson u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); 11773df57bcfSMattias Nilsson 11783df57bcfSMattias Nilsson if (!enable) 11793df57bcfSMattias Nilsson val |= PRCM_TCR_STOP_TIMERS; 11803df57bcfSMattias Nilsson writel(val, (_PRCMU_BASE + PRCM_TCR)); 11813df57bcfSMattias Nilsson 11823df57bcfSMattias Nilsson return 0; 11833df57bcfSMattias Nilsson } 11843df57bcfSMattias Nilsson 11853df57bcfSMattias Nilsson static int request_reg_clock(u8 clock, bool enable) 11863df57bcfSMattias Nilsson { 11873df57bcfSMattias Nilsson u32 val; 11883df57bcfSMattias Nilsson unsigned long flags; 11893df57bcfSMattias Nilsson 11903df57bcfSMattias Nilsson spin_lock_irqsave(&clk_mgt_lock, flags); 11913df57bcfSMattias Nilsson 11923df57bcfSMattias Nilsson /* Grab the HW semaphore. */ 11933df57bcfSMattias Nilsson while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) 11943df57bcfSMattias Nilsson cpu_relax(); 11953df57bcfSMattias Nilsson 11963df57bcfSMattias Nilsson val = readl(_PRCMU_BASE + clk_mgt[clock].offset); 11973df57bcfSMattias Nilsson if (enable) { 11983df57bcfSMattias Nilsson val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw); 11993df57bcfSMattias Nilsson } else { 12003df57bcfSMattias Nilsson clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK); 12013df57bcfSMattias Nilsson val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK); 12023df57bcfSMattias Nilsson } 12033df57bcfSMattias Nilsson writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); 12043df57bcfSMattias Nilsson 12053df57bcfSMattias Nilsson /* Release the HW semaphore. */ 12063df57bcfSMattias Nilsson writel(0, (_PRCMU_BASE + PRCM_SEM)); 12073df57bcfSMattias Nilsson 12083df57bcfSMattias Nilsson spin_unlock_irqrestore(&clk_mgt_lock, flags); 12093df57bcfSMattias Nilsson 12103df57bcfSMattias Nilsson return 0; 12113df57bcfSMattias Nilsson } 12123df57bcfSMattias Nilsson 12133df57bcfSMattias Nilsson /** 12143df57bcfSMattias Nilsson * prcmu_request_clock() - Request for a clock to be enabled or disabled. 12153df57bcfSMattias Nilsson * @clock: The clock for which the request is made. 12163df57bcfSMattias Nilsson * @enable: Whether the clock should be enabled (true) or disabled (false). 12173df57bcfSMattias Nilsson * 12183df57bcfSMattias Nilsson * This function should only be used by the clock implementation. 12193df57bcfSMattias Nilsson * Do not use it from any other place! 12203df57bcfSMattias Nilsson */ 12213df57bcfSMattias Nilsson int prcmu_request_clock(u8 clock, bool enable) 12223df57bcfSMattias Nilsson { 12233df57bcfSMattias Nilsson if (clock < PRCMU_NUM_REG_CLOCKS) 12243df57bcfSMattias Nilsson return request_reg_clock(clock, enable); 12253df57bcfSMattias Nilsson else if (clock == PRCMU_TIMCLK) 12263df57bcfSMattias Nilsson return request_timclk(enable); 12273df57bcfSMattias Nilsson else if (clock == PRCMU_SYSCLK) 12283df57bcfSMattias Nilsson return request_sysclk(enable); 12293df57bcfSMattias Nilsson else 12303df57bcfSMattias Nilsson return -EINVAL; 12313df57bcfSMattias Nilsson } 12323df57bcfSMattias Nilsson 12333df57bcfSMattias Nilsson int prcmu_config_esram0_deep_sleep(u8 state) 12343df57bcfSMattias Nilsson { 12353df57bcfSMattias Nilsson if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) || 12363df57bcfSMattias Nilsson (state < ESRAM0_DEEP_SLEEP_STATE_OFF)) 12373df57bcfSMattias Nilsson return -EINVAL; 12383df57bcfSMattias Nilsson 12393df57bcfSMattias Nilsson mutex_lock(&mb4_transfer.lock); 12403df57bcfSMattias Nilsson 12413df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) 12423df57bcfSMattias Nilsson cpu_relax(); 12433df57bcfSMattias Nilsson 12443df57bcfSMattias Nilsson writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); 12453df57bcfSMattias Nilsson writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON), 12463df57bcfSMattias Nilsson (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE)); 12473df57bcfSMattias Nilsson writeb(DDR_PWR_STATE_ON, 12483df57bcfSMattias Nilsson (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE)); 12493df57bcfSMattias Nilsson writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST)); 12503df57bcfSMattias Nilsson 12513df57bcfSMattias Nilsson writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 12523df57bcfSMattias Nilsson wait_for_completion(&mb4_transfer.work); 12533df57bcfSMattias Nilsson 12543df57bcfSMattias Nilsson mutex_unlock(&mb4_transfer.lock); 12553df57bcfSMattias Nilsson 12563df57bcfSMattias Nilsson return 0; 12573df57bcfSMattias Nilsson } 12583df57bcfSMattias Nilsson 12593df57bcfSMattias Nilsson int prcmu_config_hotdog(u8 threshold) 12603df57bcfSMattias Nilsson { 12613df57bcfSMattias Nilsson mutex_lock(&mb4_transfer.lock); 12623df57bcfSMattias Nilsson 12633df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) 12643df57bcfSMattias Nilsson cpu_relax(); 12653df57bcfSMattias Nilsson 12663df57bcfSMattias Nilsson writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD)); 12673df57bcfSMattias Nilsson writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); 12683df57bcfSMattias Nilsson 12693df57bcfSMattias Nilsson writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 12703df57bcfSMattias Nilsson wait_for_completion(&mb4_transfer.work); 12713df57bcfSMattias Nilsson 12723df57bcfSMattias Nilsson mutex_unlock(&mb4_transfer.lock); 12733df57bcfSMattias Nilsson 12743df57bcfSMattias Nilsson return 0; 12753df57bcfSMattias Nilsson } 12763df57bcfSMattias Nilsson 12773df57bcfSMattias Nilsson int prcmu_config_hotmon(u8 low, u8 high) 12783df57bcfSMattias Nilsson { 12793df57bcfSMattias Nilsson mutex_lock(&mb4_transfer.lock); 12803df57bcfSMattias Nilsson 12813df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) 12823df57bcfSMattias Nilsson cpu_relax(); 12833df57bcfSMattias Nilsson 12843df57bcfSMattias Nilsson writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW)); 12853df57bcfSMattias Nilsson writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH)); 12863df57bcfSMattias Nilsson writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH), 12873df57bcfSMattias Nilsson (tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG)); 12883df57bcfSMattias Nilsson writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); 12893df57bcfSMattias Nilsson 12903df57bcfSMattias Nilsson writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 12913df57bcfSMattias Nilsson wait_for_completion(&mb4_transfer.work); 12923df57bcfSMattias Nilsson 12933df57bcfSMattias Nilsson mutex_unlock(&mb4_transfer.lock); 12943df57bcfSMattias Nilsson 12953df57bcfSMattias Nilsson return 0; 12963df57bcfSMattias Nilsson } 12973df57bcfSMattias Nilsson 12983df57bcfSMattias Nilsson static int config_hot_period(u16 val) 12993df57bcfSMattias Nilsson { 13003df57bcfSMattias Nilsson mutex_lock(&mb4_transfer.lock); 13013df57bcfSMattias Nilsson 13023df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4)) 13033df57bcfSMattias Nilsson cpu_relax(); 13043df57bcfSMattias Nilsson 13053df57bcfSMattias Nilsson writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD)); 13063df57bcfSMattias Nilsson writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4)); 13073df57bcfSMattias Nilsson 13083df57bcfSMattias Nilsson writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 13093df57bcfSMattias Nilsson wait_for_completion(&mb4_transfer.work); 13103df57bcfSMattias Nilsson 13113df57bcfSMattias Nilsson mutex_unlock(&mb4_transfer.lock); 13123df57bcfSMattias Nilsson 13133df57bcfSMattias Nilsson return 0; 13143df57bcfSMattias Nilsson } 13153df57bcfSMattias Nilsson 13163df57bcfSMattias Nilsson int prcmu_start_temp_sense(u16 cycles32k) 13173df57bcfSMattias Nilsson { 13183df57bcfSMattias Nilsson if (cycles32k == 0xFFFF) 13193df57bcfSMattias Nilsson return -EINVAL; 13203df57bcfSMattias Nilsson 13213df57bcfSMattias Nilsson return config_hot_period(cycles32k); 13223df57bcfSMattias Nilsson } 13233df57bcfSMattias Nilsson 13243df57bcfSMattias Nilsson int prcmu_stop_temp_sense(void) 13253df57bcfSMattias Nilsson { 13263df57bcfSMattias Nilsson return config_hot_period(0xFFFF); 13273df57bcfSMattias Nilsson } 13283df57bcfSMattias Nilsson 13293df57bcfSMattias Nilsson /** 13303df57bcfSMattias Nilsson * prcmu_set_clock_divider() - Configure the clock divider. 13313df57bcfSMattias Nilsson * @clock: The clock for which the request is made. 13323df57bcfSMattias Nilsson * @divider: The clock divider. (< 32) 13333df57bcfSMattias Nilsson * 13343df57bcfSMattias Nilsson * This function should only be used by the clock implementation. 13353df57bcfSMattias Nilsson * Do not use it from any other place! 13363df57bcfSMattias Nilsson */ 13373df57bcfSMattias Nilsson int prcmu_set_clock_divider(u8 clock, u8 divider) 13383df57bcfSMattias Nilsson { 13393df57bcfSMattias Nilsson u32 val; 13403df57bcfSMattias Nilsson unsigned long flags; 13413df57bcfSMattias Nilsson 13423df57bcfSMattias Nilsson if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider)) 13433df57bcfSMattias Nilsson return -EINVAL; 13443df57bcfSMattias Nilsson 13453df57bcfSMattias Nilsson spin_lock_irqsave(&clk_mgt_lock, flags); 13463df57bcfSMattias Nilsson 13473df57bcfSMattias Nilsson /* Grab the HW semaphore. */ 13483df57bcfSMattias Nilsson while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) 13493df57bcfSMattias Nilsson cpu_relax(); 13503df57bcfSMattias Nilsson 13513df57bcfSMattias Nilsson val = readl(_PRCMU_BASE + clk_mgt[clock].offset); 13523df57bcfSMattias Nilsson val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK); 13533df57bcfSMattias Nilsson val |= (u32)divider; 13543df57bcfSMattias Nilsson writel(val, (_PRCMU_BASE + clk_mgt[clock].offset)); 13553df57bcfSMattias Nilsson 13563df57bcfSMattias Nilsson /* Release the HW semaphore. */ 13573df57bcfSMattias Nilsson writel(0, (_PRCMU_BASE + PRCM_SEM)); 13583df57bcfSMattias Nilsson 13593df57bcfSMattias Nilsson spin_unlock_irqrestore(&clk_mgt_lock, flags); 13603df57bcfSMattias Nilsson 13613df57bcfSMattias Nilsson return 0; 13623df57bcfSMattias Nilsson } 13633df57bcfSMattias Nilsson 1364650c2a21SLinus Walleij /** 1365650c2a21SLinus Walleij * prcmu_abb_read() - Read register value(s) from the ABB. 1366650c2a21SLinus Walleij * @slave: The I2C slave address. 1367650c2a21SLinus Walleij * @reg: The (start) register address. 1368650c2a21SLinus Walleij * @value: The read out value(s). 1369650c2a21SLinus Walleij * @size: The number of registers to read. 1370650c2a21SLinus Walleij * 1371650c2a21SLinus Walleij * Reads register value(s) from the ABB. 1372650c2a21SLinus Walleij * @size has to be 1 for the current firmware version. 1373650c2a21SLinus Walleij */ 1374650c2a21SLinus Walleij int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) 1375650c2a21SLinus Walleij { 1376650c2a21SLinus Walleij int r; 1377650c2a21SLinus Walleij 1378650c2a21SLinus Walleij if (size != 1) 1379650c2a21SLinus Walleij return -EINVAL; 1380650c2a21SLinus Walleij 13813df57bcfSMattias Nilsson mutex_lock(&mb5_transfer.lock); 1382650c2a21SLinus Walleij 13833df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) 1384650c2a21SLinus Walleij cpu_relax(); 1385650c2a21SLinus Walleij 13863df57bcfSMattias Nilsson writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP)); 13873df57bcfSMattias Nilsson writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS)); 13883df57bcfSMattias Nilsson writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG)); 13893df57bcfSMattias Nilsson writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL)); 1390650c2a21SLinus Walleij 13913df57bcfSMattias Nilsson writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 13923df57bcfSMattias Nilsson 1393650c2a21SLinus Walleij if (!wait_for_completion_timeout(&mb5_transfer.work, 13943df57bcfSMattias Nilsson msecs_to_jiffies(20000))) { 13953df57bcfSMattias Nilsson pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", 13963df57bcfSMattias Nilsson __func__); 1397650c2a21SLinus Walleij r = -EIO; 13983df57bcfSMattias Nilsson } else { 1399650c2a21SLinus Walleij r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO); 14003df57bcfSMattias Nilsson } 14013df57bcfSMattias Nilsson 1402650c2a21SLinus Walleij if (!r) 1403650c2a21SLinus Walleij *value = mb5_transfer.ack.value; 1404650c2a21SLinus Walleij 1405650c2a21SLinus Walleij mutex_unlock(&mb5_transfer.lock); 14063df57bcfSMattias Nilsson 1407650c2a21SLinus Walleij return r; 1408650c2a21SLinus Walleij } 1409650c2a21SLinus Walleij 1410650c2a21SLinus Walleij /** 1411650c2a21SLinus Walleij * prcmu_abb_write() - Write register value(s) to the ABB. 1412650c2a21SLinus Walleij * @slave: The I2C slave address. 1413650c2a21SLinus Walleij * @reg: The (start) register address. 1414650c2a21SLinus Walleij * @value: The value(s) to write. 1415650c2a21SLinus Walleij * @size: The number of registers to write. 1416650c2a21SLinus Walleij * 1417650c2a21SLinus Walleij * Reads register value(s) from the ABB. 1418650c2a21SLinus Walleij * @size has to be 1 for the current firmware version. 1419650c2a21SLinus Walleij */ 1420650c2a21SLinus Walleij int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) 1421650c2a21SLinus Walleij { 1422650c2a21SLinus Walleij int r; 1423650c2a21SLinus Walleij 1424650c2a21SLinus Walleij if (size != 1) 1425650c2a21SLinus Walleij return -EINVAL; 1426650c2a21SLinus Walleij 14273df57bcfSMattias Nilsson mutex_lock(&mb5_transfer.lock); 1428650c2a21SLinus Walleij 14293df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) 1430650c2a21SLinus Walleij cpu_relax(); 1431650c2a21SLinus Walleij 14323df57bcfSMattias Nilsson writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP)); 14333df57bcfSMattias Nilsson writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS)); 14343df57bcfSMattias Nilsson writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG)); 14353df57bcfSMattias Nilsson writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL)); 1436650c2a21SLinus Walleij 14373df57bcfSMattias Nilsson writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 14383df57bcfSMattias Nilsson 1439650c2a21SLinus Walleij if (!wait_for_completion_timeout(&mb5_transfer.work, 14403df57bcfSMattias Nilsson msecs_to_jiffies(20000))) { 14413df57bcfSMattias Nilsson pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", 14423df57bcfSMattias Nilsson __func__); 1443650c2a21SLinus Walleij r = -EIO; 14443df57bcfSMattias Nilsson } else { 1445650c2a21SLinus Walleij r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO); 14463df57bcfSMattias Nilsson } 14473df57bcfSMattias Nilsson 14483df57bcfSMattias Nilsson mutex_unlock(&mb5_transfer.lock); 14493df57bcfSMattias Nilsson 14503df57bcfSMattias Nilsson return r; 14513df57bcfSMattias Nilsson } 14523df57bcfSMattias Nilsson 14533df57bcfSMattias Nilsson /** 14543df57bcfSMattias Nilsson * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem 14553df57bcfSMattias Nilsson */ 14563df57bcfSMattias Nilsson void prcmu_ac_wake_req(void) 14573df57bcfSMattias Nilsson { 14583df57bcfSMattias Nilsson u32 val; 14593df57bcfSMattias Nilsson 14603df57bcfSMattias Nilsson mutex_lock(&mb0_transfer.ac_wake_lock); 14613df57bcfSMattias Nilsson 14623df57bcfSMattias Nilsson val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ); 14633df57bcfSMattias Nilsson if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ) 14643df57bcfSMattias Nilsson goto unlock_and_return; 14653df57bcfSMattias Nilsson 14663df57bcfSMattias Nilsson atomic_set(&ac_wake_req_state, 1); 14673df57bcfSMattias Nilsson 14683df57bcfSMattias Nilsson writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), 14693df57bcfSMattias Nilsson (_PRCMU_BASE + PRCM_HOSTACCESS_REQ)); 14703df57bcfSMattias Nilsson 14713df57bcfSMattias Nilsson if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, 14723df57bcfSMattias Nilsson msecs_to_jiffies(20000))) { 14733df57bcfSMattias Nilsson pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", 14743df57bcfSMattias Nilsson __func__); 14753df57bcfSMattias Nilsson } 1476650c2a21SLinus Walleij 1477650c2a21SLinus Walleij unlock_and_return: 14783df57bcfSMattias Nilsson mutex_unlock(&mb0_transfer.ac_wake_lock); 1479650c2a21SLinus Walleij } 1480650c2a21SLinus Walleij 14813df57bcfSMattias Nilsson /** 14823df57bcfSMattias Nilsson * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem 14833df57bcfSMattias Nilsson */ 14843df57bcfSMattias Nilsson void prcmu_ac_sleep_req() 1485650c2a21SLinus Walleij { 14863df57bcfSMattias Nilsson u32 val; 1487650c2a21SLinus Walleij 14883df57bcfSMattias Nilsson mutex_lock(&mb0_transfer.ac_wake_lock); 1489650c2a21SLinus Walleij 14903df57bcfSMattias Nilsson val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ); 14913df57bcfSMattias Nilsson if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)) 14923df57bcfSMattias Nilsson goto unlock_and_return; 14933df57bcfSMattias Nilsson 14943df57bcfSMattias Nilsson writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ), 14953df57bcfSMattias Nilsson (_PRCMU_BASE + PRCM_HOSTACCESS_REQ)); 14963df57bcfSMattias Nilsson 14973df57bcfSMattias Nilsson if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, 14983df57bcfSMattias Nilsson msecs_to_jiffies(20000))) { 14993df57bcfSMattias Nilsson pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n", 15003df57bcfSMattias Nilsson __func__); 15013df57bcfSMattias Nilsson } 15023df57bcfSMattias Nilsson 15033df57bcfSMattias Nilsson atomic_set(&ac_wake_req_state, 0); 15043df57bcfSMattias Nilsson 15053df57bcfSMattias Nilsson unlock_and_return: 15063df57bcfSMattias Nilsson mutex_unlock(&mb0_transfer.ac_wake_lock); 15073df57bcfSMattias Nilsson } 15083df57bcfSMattias Nilsson 15093df57bcfSMattias Nilsson bool prcmu_is_ac_wake_requested(void) 15103df57bcfSMattias Nilsson { 15113df57bcfSMattias Nilsson return (atomic_read(&ac_wake_req_state) != 0); 15123df57bcfSMattias Nilsson } 15133df57bcfSMattias Nilsson 15143df57bcfSMattias Nilsson /** 15153df57bcfSMattias Nilsson * prcmu_system_reset - System reset 15163df57bcfSMattias Nilsson * 15173df57bcfSMattias Nilsson * Saves the reset reason code and then sets the APE_SOFRST register which 15183df57bcfSMattias Nilsson * fires interrupt to fw 15193df57bcfSMattias Nilsson */ 15203df57bcfSMattias Nilsson void prcmu_system_reset(u16 reset_code) 15213df57bcfSMattias Nilsson { 15223df57bcfSMattias Nilsson writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON)); 15233df57bcfSMattias Nilsson writel(1, (_PRCMU_BASE + PRCM_APE_SOFTRST)); 15243df57bcfSMattias Nilsson } 15253df57bcfSMattias Nilsson 15263df57bcfSMattias Nilsson /** 15273df57bcfSMattias Nilsson * prcmu_reset_modem - ask the PRCMU to reset modem 15283df57bcfSMattias Nilsson */ 15293df57bcfSMattias Nilsson void prcmu_modem_reset(void) 15303df57bcfSMattias Nilsson { 1531650c2a21SLinus Walleij mutex_lock(&mb1_transfer.lock); 1532650c2a21SLinus Walleij 15333df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1)) 1534650c2a21SLinus Walleij cpu_relax(); 1535650c2a21SLinus Walleij 15363df57bcfSMattias Nilsson writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1)); 15373df57bcfSMattias Nilsson writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 1538650c2a21SLinus Walleij wait_for_completion(&mb1_transfer.work); 15393df57bcfSMattias Nilsson 15403df57bcfSMattias Nilsson /* 15413df57bcfSMattias Nilsson * No need to check return from PRCMU as modem should go in reset state 15423df57bcfSMattias Nilsson * This state is already managed by upper layer 15433df57bcfSMattias Nilsson */ 1544650c2a21SLinus Walleij 1545650c2a21SLinus Walleij mutex_unlock(&mb1_transfer.lock); 1546650c2a21SLinus Walleij } 1547650c2a21SLinus Walleij 15483df57bcfSMattias Nilsson static void ack_dbb_wakeup(void) 1549650c2a21SLinus Walleij { 15503df57bcfSMattias Nilsson unsigned long flags; 1551650c2a21SLinus Walleij 15523df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.lock, flags); 1553650c2a21SLinus Walleij 15543df57bcfSMattias Nilsson while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) 15553df57bcfSMattias Nilsson cpu_relax(); 1556650c2a21SLinus Walleij 15573df57bcfSMattias Nilsson writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0)); 15583df57bcfSMattias Nilsson writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET)); 1559650c2a21SLinus Walleij 15603df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.lock, flags); 1561650c2a21SLinus Walleij } 1562650c2a21SLinus Walleij 15633df57bcfSMattias Nilsson static inline void print_unknown_header_warning(u8 n, u8 header) 1564650c2a21SLinus Walleij { 15653df57bcfSMattias Nilsson pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n", 15663df57bcfSMattias Nilsson header, n); 1567650c2a21SLinus Walleij } 1568650c2a21SLinus Walleij 15693df57bcfSMattias Nilsson static bool read_mailbox_0(void) 1570650c2a21SLinus Walleij { 15713df57bcfSMattias Nilsson bool r; 15723df57bcfSMattias Nilsson u32 ev; 15733df57bcfSMattias Nilsson unsigned int n; 15743df57bcfSMattias Nilsson u8 header; 15753df57bcfSMattias Nilsson 15763df57bcfSMattias Nilsson header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0); 15773df57bcfSMattias Nilsson switch (header) { 15783df57bcfSMattias Nilsson case MB0H_WAKEUP_EXE: 15793df57bcfSMattias Nilsson case MB0H_WAKEUP_SLEEP: 15803df57bcfSMattias Nilsson if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1) 15813df57bcfSMattias Nilsson ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500); 15823df57bcfSMattias Nilsson else 15833df57bcfSMattias Nilsson ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500); 15843df57bcfSMattias Nilsson 15853df57bcfSMattias Nilsson if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK)) 15863df57bcfSMattias Nilsson complete(&mb0_transfer.ac_wake_work); 15873df57bcfSMattias Nilsson if (ev & WAKEUP_BIT_SYSCLK_OK) 15883df57bcfSMattias Nilsson complete(&mb3_transfer.sysclk_work); 15893df57bcfSMattias Nilsson 15903df57bcfSMattias Nilsson ev &= mb0_transfer.req.dbb_irqs; 15913df57bcfSMattias Nilsson 15923df57bcfSMattias Nilsson for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) { 15933df57bcfSMattias Nilsson if (ev & prcmu_irq_bit[n]) 15943df57bcfSMattias Nilsson generic_handle_irq(IRQ_PRCMU_BASE + n); 15953df57bcfSMattias Nilsson } 15963df57bcfSMattias Nilsson r = true; 15973df57bcfSMattias Nilsson break; 15983df57bcfSMattias Nilsson default: 15993df57bcfSMattias Nilsson print_unknown_header_warning(0, header); 16003df57bcfSMattias Nilsson r = false; 16013df57bcfSMattias Nilsson break; 16023df57bcfSMattias Nilsson } 16033df57bcfSMattias Nilsson writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 16043df57bcfSMattias Nilsson return r; 16053df57bcfSMattias Nilsson } 16063df57bcfSMattias Nilsson 16073df57bcfSMattias Nilsson static bool read_mailbox_1(void) 16083df57bcfSMattias Nilsson { 16093df57bcfSMattias Nilsson mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1); 16103df57bcfSMattias Nilsson mb1_transfer.ack.arm_opp = readb(tcdm_base + 16113df57bcfSMattias Nilsson PRCM_ACK_MB1_CURRENT_ARM_OPP); 16123df57bcfSMattias Nilsson mb1_transfer.ack.ape_opp = readb(tcdm_base + 16133df57bcfSMattias Nilsson PRCM_ACK_MB1_CURRENT_APE_OPP); 16143df57bcfSMattias Nilsson mb1_transfer.ack.ape_voltage_status = readb(tcdm_base + 16153df57bcfSMattias Nilsson PRCM_ACK_MB1_APE_VOLTAGE_STATUS); 16163df57bcfSMattias Nilsson writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 1617650c2a21SLinus Walleij complete(&mb1_transfer.work); 16183df57bcfSMattias Nilsson return false; 1619650c2a21SLinus Walleij } 1620650c2a21SLinus Walleij 16213df57bcfSMattias Nilsson static bool read_mailbox_2(void) 1622650c2a21SLinus Walleij { 16233df57bcfSMattias Nilsson mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS); 16243df57bcfSMattias Nilsson writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 16253df57bcfSMattias Nilsson complete(&mb2_transfer.work); 16263df57bcfSMattias Nilsson return false; 1627650c2a21SLinus Walleij } 1628650c2a21SLinus Walleij 16293df57bcfSMattias Nilsson static bool read_mailbox_3(void) 1630650c2a21SLinus Walleij { 16313df57bcfSMattias Nilsson writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 16323df57bcfSMattias Nilsson return false; 1633650c2a21SLinus Walleij } 1634650c2a21SLinus Walleij 16353df57bcfSMattias Nilsson static bool read_mailbox_4(void) 1636650c2a21SLinus Walleij { 16373df57bcfSMattias Nilsson u8 header; 16383df57bcfSMattias Nilsson bool do_complete = true; 16393df57bcfSMattias Nilsson 16403df57bcfSMattias Nilsson header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4); 16413df57bcfSMattias Nilsson switch (header) { 16423df57bcfSMattias Nilsson case MB4H_MEM_ST: 16433df57bcfSMattias Nilsson case MB4H_HOTDOG: 16443df57bcfSMattias Nilsson case MB4H_HOTMON: 16453df57bcfSMattias Nilsson case MB4H_HOT_PERIOD: 16463df57bcfSMattias Nilsson break; 16473df57bcfSMattias Nilsson default: 16483df57bcfSMattias Nilsson print_unknown_header_warning(4, header); 16493df57bcfSMattias Nilsson do_complete = false; 16503df57bcfSMattias Nilsson break; 1651650c2a21SLinus Walleij } 1652650c2a21SLinus Walleij 16533df57bcfSMattias Nilsson writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 16543df57bcfSMattias Nilsson 16553df57bcfSMattias Nilsson if (do_complete) 16563df57bcfSMattias Nilsson complete(&mb4_transfer.work); 16573df57bcfSMattias Nilsson 16583df57bcfSMattias Nilsson return false; 16593df57bcfSMattias Nilsson } 16603df57bcfSMattias Nilsson 16613df57bcfSMattias Nilsson static bool read_mailbox_5(void) 1662650c2a21SLinus Walleij { 16633df57bcfSMattias Nilsson mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS); 16643df57bcfSMattias Nilsson mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL); 16653df57bcfSMattias Nilsson writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 1666650c2a21SLinus Walleij complete(&mb5_transfer.work); 16673df57bcfSMattias Nilsson return false; 1668650c2a21SLinus Walleij } 1669650c2a21SLinus Walleij 16703df57bcfSMattias Nilsson static bool read_mailbox_6(void) 1671650c2a21SLinus Walleij { 16723df57bcfSMattias Nilsson writel(MBOX_BIT(6), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 16733df57bcfSMattias Nilsson return false; 1674650c2a21SLinus Walleij } 1675650c2a21SLinus Walleij 16763df57bcfSMattias Nilsson static bool read_mailbox_7(void) 1677650c2a21SLinus Walleij { 16783df57bcfSMattias Nilsson writel(MBOX_BIT(7), (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 16793df57bcfSMattias Nilsson return false; 1680650c2a21SLinus Walleij } 1681650c2a21SLinus Walleij 16823df57bcfSMattias Nilsson static bool (* const read_mailbox[NUM_MB])(void) = { 1683650c2a21SLinus Walleij read_mailbox_0, 1684650c2a21SLinus Walleij read_mailbox_1, 1685650c2a21SLinus Walleij read_mailbox_2, 1686650c2a21SLinus Walleij read_mailbox_3, 1687650c2a21SLinus Walleij read_mailbox_4, 1688650c2a21SLinus Walleij read_mailbox_5, 1689650c2a21SLinus Walleij read_mailbox_6, 1690650c2a21SLinus Walleij read_mailbox_7 1691650c2a21SLinus Walleij }; 1692650c2a21SLinus Walleij 1693650c2a21SLinus Walleij static irqreturn_t prcmu_irq_handler(int irq, void *data) 1694650c2a21SLinus Walleij { 1695650c2a21SLinus Walleij u32 bits; 1696650c2a21SLinus Walleij u8 n; 16973df57bcfSMattias Nilsson irqreturn_t r; 1698650c2a21SLinus Walleij 16993df57bcfSMattias Nilsson bits = (readl(_PRCMU_BASE + PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS); 1700650c2a21SLinus Walleij if (unlikely(!bits)) 1701650c2a21SLinus Walleij return IRQ_NONE; 1702650c2a21SLinus Walleij 17033df57bcfSMattias Nilsson r = IRQ_HANDLED; 1704650c2a21SLinus Walleij for (n = 0; bits; n++) { 1705650c2a21SLinus Walleij if (bits & MBOX_BIT(n)) { 1706650c2a21SLinus Walleij bits -= MBOX_BIT(n); 17073df57bcfSMattias Nilsson if (read_mailbox[n]()) 17083df57bcfSMattias Nilsson r = IRQ_WAKE_THREAD; 1709650c2a21SLinus Walleij } 1710650c2a21SLinus Walleij } 17113df57bcfSMattias Nilsson return r; 17123df57bcfSMattias Nilsson } 17133df57bcfSMattias Nilsson 17143df57bcfSMattias Nilsson static irqreturn_t prcmu_irq_thread_fn(int irq, void *data) 17153df57bcfSMattias Nilsson { 17163df57bcfSMattias Nilsson ack_dbb_wakeup(); 1717650c2a21SLinus Walleij return IRQ_HANDLED; 1718650c2a21SLinus Walleij } 1719650c2a21SLinus Walleij 17203df57bcfSMattias Nilsson static void prcmu_mask_work(struct work_struct *work) 17213df57bcfSMattias Nilsson { 17223df57bcfSMattias Nilsson unsigned long flags; 17233df57bcfSMattias Nilsson 17243df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.lock, flags); 17253df57bcfSMattias Nilsson 17263df57bcfSMattias Nilsson config_wakeups(); 17273df57bcfSMattias Nilsson 17283df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.lock, flags); 17293df57bcfSMattias Nilsson } 17303df57bcfSMattias Nilsson 17313df57bcfSMattias Nilsson static void prcmu_irq_mask(struct irq_data *d) 17323df57bcfSMattias Nilsson { 17333df57bcfSMattias Nilsson unsigned long flags; 17343df57bcfSMattias Nilsson 17353df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); 17363df57bcfSMattias Nilsson 17373df57bcfSMattias Nilsson mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; 17383df57bcfSMattias Nilsson 17393df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); 17403df57bcfSMattias Nilsson 17413df57bcfSMattias Nilsson if (d->irq != IRQ_PRCMU_CA_SLEEP) 17423df57bcfSMattias Nilsson schedule_work(&mb0_transfer.mask_work); 17433df57bcfSMattias Nilsson } 17443df57bcfSMattias Nilsson 17453df57bcfSMattias Nilsson static void prcmu_irq_unmask(struct irq_data *d) 17463df57bcfSMattias Nilsson { 17473df57bcfSMattias Nilsson unsigned long flags; 17483df57bcfSMattias Nilsson 17493df57bcfSMattias Nilsson spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); 17503df57bcfSMattias Nilsson 17513df57bcfSMattias Nilsson mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; 17523df57bcfSMattias Nilsson 17533df57bcfSMattias Nilsson spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); 17543df57bcfSMattias Nilsson 17553df57bcfSMattias Nilsson if (d->irq != IRQ_PRCMU_CA_SLEEP) 17563df57bcfSMattias Nilsson schedule_work(&mb0_transfer.mask_work); 17573df57bcfSMattias Nilsson } 17583df57bcfSMattias Nilsson 17593df57bcfSMattias Nilsson static void noop(struct irq_data *d) 17603df57bcfSMattias Nilsson { 17613df57bcfSMattias Nilsson } 17623df57bcfSMattias Nilsson 17633df57bcfSMattias Nilsson static struct irq_chip prcmu_irq_chip = { 17643df57bcfSMattias Nilsson .name = "prcmu", 17653df57bcfSMattias Nilsson .irq_disable = prcmu_irq_mask, 17663df57bcfSMattias Nilsson .irq_ack = noop, 17673df57bcfSMattias Nilsson .irq_mask = prcmu_irq_mask, 17683df57bcfSMattias Nilsson .irq_unmask = prcmu_irq_unmask, 17693df57bcfSMattias Nilsson }; 17703df57bcfSMattias Nilsson 1771650c2a21SLinus Walleij void __init prcmu_early_init(void) 1772650c2a21SLinus Walleij { 17733df57bcfSMattias Nilsson unsigned int i; 17743df57bcfSMattias Nilsson 17753df57bcfSMattias Nilsson if (cpu_is_u8500v1()) { 1776650c2a21SLinus Walleij tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1); 1777650c2a21SLinus Walleij } else if (cpu_is_u8500v2()) { 17783df57bcfSMattias Nilsson void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); 17793df57bcfSMattias Nilsson 17803df57bcfSMattias Nilsson if (tcpm_base != NULL) { 17813df57bcfSMattias Nilsson int version; 17823df57bcfSMattias Nilsson version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET); 17833df57bcfSMattias Nilsson prcmu_version.project_number = version & 0xFF; 17843df57bcfSMattias Nilsson prcmu_version.api_version = (version >> 8) & 0xFF; 17853df57bcfSMattias Nilsson prcmu_version.func_version = (version >> 16) & 0xFF; 17863df57bcfSMattias Nilsson prcmu_version.errata = (version >> 24) & 0xFF; 17873df57bcfSMattias Nilsson pr_info("PRCMU firmware version %d.%d.%d\n", 17883df57bcfSMattias Nilsson (version >> 8) & 0xFF, (version >> 16) & 0xFF, 17893df57bcfSMattias Nilsson (version >> 24) & 0xFF); 17903df57bcfSMattias Nilsson iounmap(tcpm_base); 17913df57bcfSMattias Nilsson } 17923df57bcfSMattias Nilsson 1793650c2a21SLinus Walleij tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); 1794650c2a21SLinus Walleij } else { 1795650c2a21SLinus Walleij pr_err("prcmu: Unsupported chip version\n"); 1796650c2a21SLinus Walleij BUG(); 1797650c2a21SLinus Walleij } 1798650c2a21SLinus Walleij 17993df57bcfSMattias Nilsson spin_lock_init(&mb0_transfer.lock); 18003df57bcfSMattias Nilsson spin_lock_init(&mb0_transfer.dbb_irqs_lock); 18013df57bcfSMattias Nilsson mutex_init(&mb0_transfer.ac_wake_lock); 18023df57bcfSMattias Nilsson init_completion(&mb0_transfer.ac_wake_work); 1803650c2a21SLinus Walleij mutex_init(&mb1_transfer.lock); 1804650c2a21SLinus Walleij init_completion(&mb1_transfer.work); 18053df57bcfSMattias Nilsson mutex_init(&mb2_transfer.lock); 18063df57bcfSMattias Nilsson init_completion(&mb2_transfer.work); 18073df57bcfSMattias Nilsson spin_lock_init(&mb2_transfer.auto_pm_lock); 18083df57bcfSMattias Nilsson spin_lock_init(&mb3_transfer.lock); 18093df57bcfSMattias Nilsson mutex_init(&mb3_transfer.sysclk_lock); 18103df57bcfSMattias Nilsson init_completion(&mb3_transfer.sysclk_work); 18113df57bcfSMattias Nilsson mutex_init(&mb4_transfer.lock); 18123df57bcfSMattias Nilsson init_completion(&mb4_transfer.work); 1813650c2a21SLinus Walleij mutex_init(&mb5_transfer.lock); 1814650c2a21SLinus Walleij init_completion(&mb5_transfer.work); 1815650c2a21SLinus Walleij 18163df57bcfSMattias Nilsson INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); 1817650c2a21SLinus Walleij 18183df57bcfSMattias Nilsson /* Initalize irqs. */ 18193df57bcfSMattias Nilsson for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) { 18203df57bcfSMattias Nilsson unsigned int irq; 18213df57bcfSMattias Nilsson 18223df57bcfSMattias Nilsson irq = IRQ_PRCMU_BASE + i; 18233df57bcfSMattias Nilsson irq_set_chip_and_handler(irq, &prcmu_irq_chip, 18243df57bcfSMattias Nilsson handle_simple_irq); 18253df57bcfSMattias Nilsson set_irq_flags(irq, IRQF_VALID); 18263df57bcfSMattias Nilsson } 1827650c2a21SLinus Walleij } 1828650c2a21SLinus Walleij 18291032fbfdSBengt Jonsson /* 18301032fbfdSBengt Jonsson * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC 18311032fbfdSBengt Jonsson */ 18321032fbfdSBengt Jonsson static struct regulator_consumer_supply db8500_vape_consumers[] = { 18331032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-ape", NULL), 18341032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"), 18351032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"), 18361032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"), 18371032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"), 18381032fbfdSBengt Jonsson /* "v-mmc" changed to "vcore" in the mainline kernel */ 18391032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "sdi0"), 18401032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "sdi1"), 18411032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "sdi2"), 18421032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "sdi3"), 18431032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "sdi4"), 18441032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-dma", "dma40.0"), 18451032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"), 18461032fbfdSBengt Jonsson /* "v-uart" changed to "vcore" in the mainline kernel */ 18471032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "uart0"), 18481032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "uart1"), 18491032fbfdSBengt Jonsson REGULATOR_SUPPLY("vcore", "uart2"), 18501032fbfdSBengt Jonsson REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"), 18511032fbfdSBengt Jonsson }; 18521032fbfdSBengt Jonsson 18531032fbfdSBengt Jonsson static struct regulator_consumer_supply db8500_vsmps2_consumers[] = { 18541032fbfdSBengt Jonsson /* CG2900 and CW1200 power to off-chip peripherals */ 18551032fbfdSBengt Jonsson REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"), 18561032fbfdSBengt Jonsson REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"), 18571032fbfdSBengt Jonsson REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"), 18581032fbfdSBengt Jonsson /* AV8100 regulator */ 18591032fbfdSBengt Jonsson REGULATOR_SUPPLY("hdmi_1v8", "0-0070"), 18601032fbfdSBengt Jonsson }; 18611032fbfdSBengt Jonsson 18621032fbfdSBengt Jonsson static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = { 18631032fbfdSBengt Jonsson REGULATOR_SUPPLY("vsupply", "b2r2.0"), 18641032fbfdSBengt Jonsson REGULATOR_SUPPLY("vsupply", "mcde.0"), 18651032fbfdSBengt Jonsson }; 18661032fbfdSBengt Jonsson 18671032fbfdSBengt Jonsson static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = { 18681032fbfdSBengt Jonsson [DB8500_REGULATOR_VAPE] = { 18691032fbfdSBengt Jonsson .constraints = { 18701032fbfdSBengt Jonsson .name = "db8500-vape", 18711032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 18721032fbfdSBengt Jonsson }, 18731032fbfdSBengt Jonsson .consumer_supplies = db8500_vape_consumers, 18741032fbfdSBengt Jonsson .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers), 18751032fbfdSBengt Jonsson }, 18761032fbfdSBengt Jonsson [DB8500_REGULATOR_VARM] = { 18771032fbfdSBengt Jonsson .constraints = { 18781032fbfdSBengt Jonsson .name = "db8500-varm", 18791032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 18801032fbfdSBengt Jonsson }, 18811032fbfdSBengt Jonsson }, 18821032fbfdSBengt Jonsson [DB8500_REGULATOR_VMODEM] = { 18831032fbfdSBengt Jonsson .constraints = { 18841032fbfdSBengt Jonsson .name = "db8500-vmodem", 18851032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 18861032fbfdSBengt Jonsson }, 18871032fbfdSBengt Jonsson }, 18881032fbfdSBengt Jonsson [DB8500_REGULATOR_VPLL] = { 18891032fbfdSBengt Jonsson .constraints = { 18901032fbfdSBengt Jonsson .name = "db8500-vpll", 18911032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 18921032fbfdSBengt Jonsson }, 18931032fbfdSBengt Jonsson }, 18941032fbfdSBengt Jonsson [DB8500_REGULATOR_VSMPS1] = { 18951032fbfdSBengt Jonsson .constraints = { 18961032fbfdSBengt Jonsson .name = "db8500-vsmps1", 18971032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 18981032fbfdSBengt Jonsson }, 18991032fbfdSBengt Jonsson }, 19001032fbfdSBengt Jonsson [DB8500_REGULATOR_VSMPS2] = { 19011032fbfdSBengt Jonsson .constraints = { 19021032fbfdSBengt Jonsson .name = "db8500-vsmps2", 19031032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19041032fbfdSBengt Jonsson }, 19051032fbfdSBengt Jonsson .consumer_supplies = db8500_vsmps2_consumers, 19061032fbfdSBengt Jonsson .num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers), 19071032fbfdSBengt Jonsson }, 19081032fbfdSBengt Jonsson [DB8500_REGULATOR_VSMPS3] = { 19091032fbfdSBengt Jonsson .constraints = { 19101032fbfdSBengt Jonsson .name = "db8500-vsmps3", 19111032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19121032fbfdSBengt Jonsson }, 19131032fbfdSBengt Jonsson }, 19141032fbfdSBengt Jonsson [DB8500_REGULATOR_VRF1] = { 19151032fbfdSBengt Jonsson .constraints = { 19161032fbfdSBengt Jonsson .name = "db8500-vrf1", 19171032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19181032fbfdSBengt Jonsson }, 19191032fbfdSBengt Jonsson }, 19201032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SVAMMDSP] = { 19211032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19221032fbfdSBengt Jonsson .constraints = { 19231032fbfdSBengt Jonsson .name = "db8500-sva-mmdsp", 19241032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19251032fbfdSBengt Jonsson }, 19261032fbfdSBengt Jonsson }, 19271032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = { 19281032fbfdSBengt Jonsson .constraints = { 19291032fbfdSBengt Jonsson /* "ret" means "retention" */ 19301032fbfdSBengt Jonsson .name = "db8500-sva-mmdsp-ret", 19311032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19321032fbfdSBengt Jonsson }, 19331032fbfdSBengt Jonsson }, 19341032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SVAPIPE] = { 19351032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19361032fbfdSBengt Jonsson .constraints = { 19371032fbfdSBengt Jonsson .name = "db8500-sva-pipe", 19381032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19391032fbfdSBengt Jonsson }, 19401032fbfdSBengt Jonsson }, 19411032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SIAMMDSP] = { 19421032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19431032fbfdSBengt Jonsson .constraints = { 19441032fbfdSBengt Jonsson .name = "db8500-sia-mmdsp", 19451032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19461032fbfdSBengt Jonsson }, 19471032fbfdSBengt Jonsson }, 19481032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = { 19491032fbfdSBengt Jonsson .constraints = { 19501032fbfdSBengt Jonsson .name = "db8500-sia-mmdsp-ret", 19511032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19521032fbfdSBengt Jonsson }, 19531032fbfdSBengt Jonsson }, 19541032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SIAPIPE] = { 19551032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19561032fbfdSBengt Jonsson .constraints = { 19571032fbfdSBengt Jonsson .name = "db8500-sia-pipe", 19581032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19591032fbfdSBengt Jonsson }, 19601032fbfdSBengt Jonsson }, 19611032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_SGA] = { 19621032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19631032fbfdSBengt Jonsson .constraints = { 19641032fbfdSBengt Jonsson .name = "db8500-sga", 19651032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19661032fbfdSBengt Jonsson }, 19671032fbfdSBengt Jonsson }, 19681032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = { 19691032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19701032fbfdSBengt Jonsson .constraints = { 19711032fbfdSBengt Jonsson .name = "db8500-b2r2-mcde", 19721032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19731032fbfdSBengt Jonsson }, 19741032fbfdSBengt Jonsson .consumer_supplies = db8500_b2r2_mcde_consumers, 19751032fbfdSBengt Jonsson .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers), 19761032fbfdSBengt Jonsson }, 19771032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_ESRAM12] = { 19781032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19791032fbfdSBengt Jonsson .constraints = { 19801032fbfdSBengt Jonsson .name = "db8500-esram12", 19811032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19821032fbfdSBengt Jonsson }, 19831032fbfdSBengt Jonsson }, 19841032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_ESRAM12RET] = { 19851032fbfdSBengt Jonsson .constraints = { 19861032fbfdSBengt Jonsson .name = "db8500-esram12-ret", 19871032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19881032fbfdSBengt Jonsson }, 19891032fbfdSBengt Jonsson }, 19901032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_ESRAM34] = { 19911032fbfdSBengt Jonsson .supply_regulator = "db8500-vape", 19921032fbfdSBengt Jonsson .constraints = { 19931032fbfdSBengt Jonsson .name = "db8500-esram34", 19941032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 19951032fbfdSBengt Jonsson }, 19961032fbfdSBengt Jonsson }, 19971032fbfdSBengt Jonsson [DB8500_REGULATOR_SWITCH_ESRAM34RET] = { 19981032fbfdSBengt Jonsson .constraints = { 19991032fbfdSBengt Jonsson .name = "db8500-esram34-ret", 20001032fbfdSBengt Jonsson .valid_ops_mask = REGULATOR_CHANGE_STATUS, 20011032fbfdSBengt Jonsson }, 20021032fbfdSBengt Jonsson }, 20031032fbfdSBengt Jonsson }; 20041032fbfdSBengt Jonsson 20053df57bcfSMattias Nilsson static struct mfd_cell db8500_prcmu_devs[] = { 20063df57bcfSMattias Nilsson { 20073df57bcfSMattias Nilsson .name = "db8500-prcmu-regulators", 20081ed7891fSMattias Wallin .platform_data = &db8500_regulators, 20091ed7891fSMattias Wallin .pdata_size = sizeof(db8500_regulators), 20103df57bcfSMattias Nilsson }, 20113df57bcfSMattias Nilsson { 20123df57bcfSMattias Nilsson .name = "cpufreq-u8500", 20133df57bcfSMattias Nilsson }, 20143df57bcfSMattias Nilsson }; 20153df57bcfSMattias Nilsson 20163df57bcfSMattias Nilsson /** 20173df57bcfSMattias Nilsson * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic 20183df57bcfSMattias Nilsson * 20193df57bcfSMattias Nilsson */ 20203df57bcfSMattias Nilsson static int __init db8500_prcmu_probe(struct platform_device *pdev) 20213df57bcfSMattias Nilsson { 20223df57bcfSMattias Nilsson int err = 0; 20233df57bcfSMattias Nilsson 20243df57bcfSMattias Nilsson if (ux500_is_svp()) 20253df57bcfSMattias Nilsson return -ENODEV; 20263df57bcfSMattias Nilsson 20273df57bcfSMattias Nilsson /* Clean up the mailbox interrupts after pre-kernel code. */ 20283df57bcfSMattias Nilsson writel(ALL_MBOX_BITS, (_PRCMU_BASE + PRCM_ARM_IT1_CLR)); 20293df57bcfSMattias Nilsson 20303df57bcfSMattias Nilsson err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 20313df57bcfSMattias Nilsson prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); 20323df57bcfSMattias Nilsson if (err < 0) { 20333df57bcfSMattias Nilsson pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n"); 20343df57bcfSMattias Nilsson err = -EBUSY; 20353df57bcfSMattias Nilsson goto no_irq_return; 20363df57bcfSMattias Nilsson } 20373df57bcfSMattias Nilsson 20383df57bcfSMattias Nilsson if (cpu_is_u8500v20_or_later()) 20393df57bcfSMattias Nilsson prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); 20403df57bcfSMattias Nilsson 20413df57bcfSMattias Nilsson err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, 20423df57bcfSMattias Nilsson ARRAY_SIZE(db8500_prcmu_devs), NULL, 20433df57bcfSMattias Nilsson 0); 20443df57bcfSMattias Nilsson 20453df57bcfSMattias Nilsson if (err) 20463df57bcfSMattias Nilsson pr_err("prcmu: Failed to add subdevices\n"); 20473df57bcfSMattias Nilsson else 20483df57bcfSMattias Nilsson pr_info("DB8500 PRCMU initialized\n"); 20493df57bcfSMattias Nilsson 20503df57bcfSMattias Nilsson no_irq_return: 20513df57bcfSMattias Nilsson return err; 20523df57bcfSMattias Nilsson } 20533df57bcfSMattias Nilsson 20543df57bcfSMattias Nilsson static struct platform_driver db8500_prcmu_driver = { 20553df57bcfSMattias Nilsson .driver = { 20563df57bcfSMattias Nilsson .name = "db8500-prcmu", 20573df57bcfSMattias Nilsson .owner = THIS_MODULE, 20583df57bcfSMattias Nilsson }, 20593df57bcfSMattias Nilsson }; 20603df57bcfSMattias Nilsson 20613df57bcfSMattias Nilsson static int __init db8500_prcmu_init(void) 20623df57bcfSMattias Nilsson { 20633df57bcfSMattias Nilsson return platform_driver_probe(&db8500_prcmu_driver, db8500_prcmu_probe); 20643df57bcfSMattias Nilsson } 20653df57bcfSMattias Nilsson 20663df57bcfSMattias Nilsson arch_initcall(db8500_prcmu_init); 20673df57bcfSMattias Nilsson 20683df57bcfSMattias Nilsson MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>"); 20693df57bcfSMattias Nilsson MODULE_DESCRIPTION("DB8500 PRCM Unit driver"); 20703df57bcfSMattias Nilsson MODULE_LICENSE("GPL v2"); 2071