diff options
author | Olof Johansson <olof@lixom.net> | 2015-01-24 01:57:23 +0300 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2015-01-24 01:57:23 +0300 |
commit | 9b865d9b5cdaa3fab78f11421243da863d6ee66a (patch) | |
tree | 5f6d052e150532f9ff5e29f57e3a6245e88aa223 /arch | |
parent | 82483ad67e965f6edd61c6c2cdb4ba295cf0af96 (diff) | |
parent | f5d3af9d21f9790ac078276e6c103871c12a3daa (diff) | |
download | linux-9b865d9b5cdaa3fab78f11421243da863d6ee66a.tar.xz |
Merge tag 'qcom-soc-for-3.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom into next/soc
merge "qcom SoC changes for v3.20-2" from Kumar Gala:
Qualcomm ARM Based SoC Updates for v3.20-2
* Various bug fixes and minor feature additions to scm code
* Added big-endian support to debug MSM uart
* Added big-endian support to ARCH_QCOM
* Cleaned up some Kconfig options associated with ARCH_QCOM
* Added Andy Gross as co-maintainer
* tag 'qcom-soc-for-3.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom:
MAINTAINERS: Add co-maintainer for ARM/Qualcomm Support
ARM: qcom: Drop unnecessary selects from ARCH_QCOM
ARM: qcom: Fix SCM interface for big-endian kernels
ARM: qcom: scm: Clarify boot interface
ARM: qcom: Add SCM warmboot flags for quad core targets.
ARM: qcom: scm: Add logging of actual return code from scm call
ARM: qcom: scm: Flush the command buffer only instead of the entire cache
ARM: qcom: scm: Get cacheline size from CTR
ARM: qcom: scm: Fix incorrect cache invalidation
ARM: qcom: Select ARCH_SUPPORTS_BIG_ENDIAN
ARM: debug: msm: Support big-endian CPUs
ARM: debug: Update MSM and QCOM DEBUG_LL help
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig.debug | 5 | ||||
-rw-r--r-- | arch/arm/include/debug/msm.S | 6 | ||||
-rw-r--r-- | arch/arm/mach-qcom/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-qcom/scm-boot.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-qcom/scm-boot.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-qcom/scm.c | 85 |
6 files changed, 74 insertions, 39 deletions
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index e902cedbb2dc..74a873ad493f 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -438,7 +438,7 @@ choice Say Y here if you want the debug print routines to direct their output to the serial port on MSM devices. - ARCH DEBUG_UART_PHYS DEBUG_UART_BASE # + ARCH DEBUG_UART_PHYS DEBUG_UART_VIRT # MSM7X00A, QSD8X50 0xa9a00000 0xe1000000 UART1 MSM7X00A, QSD8X50 0xa9b00000 0xe1000000 UART2 MSM7X00A, QSD8X50 0xa9c00000 0xe1000000 UART3 @@ -457,7 +457,8 @@ choice Say Y here if you want the debug print routines to direct their output to the serial port on Qualcomm devices. - ARCH DEBUG_UART_PHYS DEBUG_UART_BASE + ARCH DEBUG_UART_PHYS DEBUG_UART_VIRT + APQ8064 0x16640000 0xf0040000 APQ8084 0xf995e000 0xfa75e000 MSM8X60 0x19c40000 0xf0040000 MSM8960 0x16440000 0xf0040000 diff --git a/arch/arm/include/debug/msm.S b/arch/arm/include/debug/msm.S index 9ef57612811d..e55a9426b496 100644 --- a/arch/arm/include/debug/msm.S +++ b/arch/arm/include/debug/msm.S @@ -23,6 +23,7 @@ .endm .macro senduart, rd, rx +ARM_BE8(rev \rd, \rd ) #ifdef CONFIG_DEBUG_QCOM_UARTDM @ Write the 1 character to UARTDM_TF str \rd, [\rx, #0x70] @@ -35,24 +36,29 @@ #ifdef CONFIG_DEBUG_QCOM_UARTDM @ check for TX_EMT in UARTDM_SR ldr \rd, [\rx, #0x08] +ARM_BE8(rev \rd, \rd ) tst \rd, #0x08 bne 1002f @ wait for TXREADY in UARTDM_ISR 1001: ldr \rd, [\rx, #0x14] +ARM_BE8(rev \rd, \rd ) tst \rd, #0x80 beq 1001b 1002: @ Clear TX_READY by writing to the UARTDM_CR register mov \rd, #0x300 +ARM_BE8(rev \rd, \rd ) str \rd, [\rx, #0x10] @ Write 0x1 to NCF register mov \rd, #0x1 +ARM_BE8(rev \rd, \rd ) str \rd, [\rx, #0x40] @ UARTDM reg. Read to induce delay ldr \rd, [\rx, #0x08] #else @ wait for TX_READY 1001: ldr \rd, [\rx, #0x08] +ARM_BE8(rev \rd, \rd ) tst \rd, #0x04 beq 1001b #endif diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index ee5697ba05bc..48003ea652b9 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -1,9 +1,8 @@ menuconfig ARCH_QCOM bool "Qualcomm Support" if ARCH_MULTI_V7 - select ARCH_REQUIRE_GPIOLIB + select ARCH_SUPPORTS_BIG_ENDIAN select ARM_GIC select ARM_AMBA - select CLKSRC_OF select PINCTRL select QCOM_SCM if SMP help diff --git a/arch/arm/mach-qcom/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c index 45cee3e469a5..e8ff7beb6218 100644 --- a/arch/arm/mach-qcom/scm-boot.c +++ b/arch/arm/mach-qcom/scm-boot.c @@ -24,15 +24,15 @@ /* * Set the cold/warm boot address for one of the CPU cores. */ -int scm_set_boot_addr(phys_addr_t addr, int flags) +int scm_set_boot_addr(u32 addr, int flags) { struct { - unsigned int flags; - phys_addr_t addr; + __le32 flags; + __le32 addr; } cmd; - cmd.addr = addr; - cmd.flags = flags; + cmd.addr = cpu_to_le32(addr); + cmd.flags = cpu_to_le32(flags); return scm_call(SCM_SVC_BOOT, SCM_BOOT_ADDR, &cmd, sizeof(cmd), NULL, 0); } diff --git a/arch/arm/mach-qcom/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h index 6aabb2428176..3e210fb818bb 100644 --- a/arch/arm/mach-qcom/scm-boot.h +++ b/arch/arm/mach-qcom/scm-boot.h @@ -18,7 +18,9 @@ #define SCM_FLAG_COLDBOOT_CPU3 0x20 #define SCM_FLAG_WARMBOOT_CPU0 0x04 #define SCM_FLAG_WARMBOOT_CPU1 0x02 +#define SCM_FLAG_WARMBOOT_CPU2 0x10 +#define SCM_FLAG_WARMBOOT_CPU3 0x40 -int scm_set_boot_addr(phys_addr_t addr, int flags); +int scm_set_boot_addr(u32 addr, int flags); #endif diff --git a/arch/arm/mach-qcom/scm.c b/arch/arm/mach-qcom/scm.c index c536fd6bf827..1d9cf18c7091 100644 --- a/arch/arm/mach-qcom/scm.c +++ b/arch/arm/mach-qcom/scm.c @@ -22,13 +22,11 @@ #include <linux/errno.h> #include <linux/err.h> +#include <asm/outercache.h> #include <asm/cacheflush.h> #include "scm.h" -/* Cache line size for msm8x60 */ -#define CACHELINESIZE 32 - #define SCM_ENOMEM -5 #define SCM_EOPNOTSUPP -4 #define SCM_EINVAL_ADDR -3 @@ -63,11 +61,11 @@ static DEFINE_MUTEX(scm_lock); * to access the buffers in a safe manner. */ struct scm_command { - u32 len; - u32 buf_offset; - u32 resp_hdr_offset; - u32 id; - u32 buf[0]; + __le32 len; + __le32 buf_offset; + __le32 resp_hdr_offset; + __le32 id; + __le32 buf[0]; }; /** @@ -77,9 +75,9 @@ struct scm_command { * @is_complete: indicates if the command has finished processing */ struct scm_response { - u32 len; - u32 buf_offset; - u32 is_complete; + __le32 len; + __le32 buf_offset; + __le32 is_complete; }; /** @@ -97,12 +95,14 @@ static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size) struct scm_command *cmd; size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size + resp_size; + u32 offset; cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); if (cmd) { - cmd->len = len; - cmd->buf_offset = offsetof(struct scm_command, buf); - cmd->resp_hdr_offset = cmd->buf_offset + cmd_size; + cmd->len = cpu_to_le32(len); + offset = offsetof(struct scm_command, buf); + cmd->buf_offset = cpu_to_le32(offset); + cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size); } return cmd; } @@ -127,7 +127,7 @@ static inline void free_scm_command(struct scm_command *cmd) static inline struct scm_response *scm_command_to_response( const struct scm_command *cmd) { - return (void *)cmd + cmd->resp_hdr_offset; + return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset); } /** @@ -149,11 +149,12 @@ static inline void *scm_get_command_buffer(const struct scm_command *cmd) */ static inline void *scm_get_response_buffer(const struct scm_response *rsp) { - return (void *)rsp + rsp->buf_offset; + return (void *)rsp + le32_to_cpu(rsp->buf_offset); } static int scm_remap_error(int err) { + pr_err("scm_call failed with error code %d\n", err); switch (err) { case SCM_ERROR: return -EIO; @@ -198,11 +199,12 @@ static int __scm_call(const struct scm_command *cmd) u32 cmd_addr = virt_to_phys(cmd); /* - * Flush the entire cache here so callers don't have to remember - * to flush the cache when passing physical addresses to the secure - * side in the buffer. + * Flush the command buffer so that the secure world sees + * the correct data. */ - flush_cache_all(); + __cpuc_flush_dcache_area((void *)cmd, cmd->len); + outer_flush_range(cmd_addr, cmd_addr + cmd->len); + ret = smc(cmd_addr); if (ret < 0) ret = scm_remap_error(ret); @@ -210,6 +212,25 @@ static int __scm_call(const struct scm_command *cmd) return ret; } +static void scm_inv_range(unsigned long start, unsigned long end) +{ + u32 cacheline_size, ctr; + + asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr)); + cacheline_size = 4 << ((ctr >> 16) & 0xf); + + start = round_down(start, cacheline_size); + end = round_up(end, cacheline_size); + outer_inv_range(start, end); + while (start < end) { + asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) + : "memory"); + start += cacheline_size; + } + dsb(); + isb(); +} + /** * scm_call() - Send an SCM command * @svc_id: service identifier @@ -220,6 +241,13 @@ static int __scm_call(const struct scm_command *cmd) * @resp_len: length of the response buffer * * Sends a command to the SCM and waits for the command to finish processing. + * + * A note on cache maintenance: + * Note that any buffers that are expected to be accessed by the secure world + * must be flushed before invoking scm_call and invalidated in the cache + * immediately after scm_call returns. Cache maintenance on the command and + * response buffers is taken care of by scm_call; however, callers are + * responsible for any other cached buffers passed over to the secure world. */ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, void *resp_buf, size_t resp_len) @@ -227,12 +255,13 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, int ret; struct scm_command *cmd; struct scm_response *rsp; + unsigned long start, end; cmd = alloc_scm_command(cmd_len, resp_len); if (!cmd) return -ENOMEM; - cmd->id = (svc_id << 10) | cmd_id; + cmd->id = cpu_to_le32((svc_id << 10) | cmd_id); if (cmd_buf) memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len); @@ -243,17 +272,15 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, goto out; rsp = scm_command_to_response(cmd); + start = (unsigned long)rsp; + do { - u32 start = (u32)rsp; - u32 end = (u32)scm_get_response_buffer(rsp) + resp_len; - start &= ~(CACHELINESIZE - 1); - while (start < end) { - asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) - : "memory"); - start += CACHELINESIZE; - } + scm_inv_range(start, start + sizeof(*rsp)); } while (!rsp->is_complete); + end = (unsigned long)scm_get_response_buffer(rsp) + resp_len; + scm_inv_range(start, end); + if (resp_buf) memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len); out: |