diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 13:35:07 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 13:35:07 -0700 |
commit | e4e47eb15b7884963efe7f98231009c5770a2c3d (patch) | |
tree | ebd3536a3aa728089168f072c88858578535046d /arch | |
parent | 711f77f53c5ff6aa61dbe8e5f518e50d6306e89d (diff) | |
parent | 7b52161d14fa8a22a2387f4aa2fb7b854587830d (diff) |
Merge branch 'msm-core' of git://codeaurora.org/quic/kernel/dwalker/linux-msm
* 'msm-core' of git://codeaurora.org/quic/kernel/dwalker/linux-msm: (72 commits)
msm: 7x30 Kconfig and makefile changes
msm: clock support for the MSM7x30 CPU.
msm: physical offset for MSM7X30
msm: io: add io support for 7x30
msm: Add extern for 7x30 clock list.
msm: dma: add 7x30 security domain abstraction
msm: update basic board layout for MSM7x30
msm: add devices-msm7x30.c
msm: add msm_iomap-7x30.h for MSM7x30 support
msm: irqs: add irqs-7x30.h for MSM7x30 support
msm: 8x50 Kconfig changes
msm: physical offset for QSD8x50
msm: io: add io support for 8x50
msm: add extern for 8x50 clock list.
msm: add devices-qsd8x50.c
msm: update basic board layout for QSD8x50
msm: add msm_iomap-8x50.h for QSD8x50 support
msm: irqs: add irqs-8x50.h for QSD8x50 support
msm: timer: allow MSM_DGT_BASE to be overriden
msm: add Qualcomm 7x30 interrupt controller driver.
...
Diffstat (limited to 'arch')
55 files changed, 6538 insertions, 453 deletions
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index b9fd5c528e5b..47264a76eeb3 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,7 +1,80 @@ if ARCH_MSM -comment "MSM Board Type" +choice + prompt "Qualcomm MSM SoC Type" + default ARCH_MSM7X00A + +config ARCH_MSM7X00A + bool "MSM7x00A / MSM7x01A" + select ARCH_MSM_ARM11 + select MSM_SMD + select MSM_SMD_PKG3 + select CPU_V6 + +config ARCH_MSM7X30 + bool "MSM7x30" + select ARCH_MSM_SCORPION + select MSM_SMD + select MSM_VIC + select CPU_V7 + select MSM_REMOTE_SPINLOCK_DEKKERS + +config ARCH_QSD8X50 + bool "QSD8X50" + select ARCH_MSM_SCORPION + select MSM_SMD + select MSM_VIC + select CPU_V7 + select MSM_REMOTE_SPINLOCK_LDREX +endchoice + +config MSM_SOC_REV_A + bool + +config ARCH_MSM_ARM11 + bool +config ARCH_MSM_SCORPION + bool + +config MSM_VIC + bool + +menu "Qualcomm MSM Board Type" + +config MACH_HALIBUT depends on ARCH_MSM + depends on ARCH_MSM7X00A + bool "Halibut Board (QCT SURF7201A)" + help + Support for the Qualcomm SURF7201A eval board. + +config MACH_TROUT + depends on ARCH_MSM + depends on ARCH_MSM7X00A + bool "HTC Dream (aka trout)" + help + Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. + +config MACH_MSM7X30_SURF + depends on ARCH_MSM7X30 + bool "MSM7x30 SURF" + help + Support for the Qualcomm MSM7x30 SURF eval board. + +config MACH_QSD8X50_SURF + depends on ARCH_QSD8X50 + bool "QSD8x50 SURF" + help + Support for the Qualcomm QSD8x50 SURF eval board. + +config MACH_QSD8X50A_ST1_5 + depends on ARCH_QSD8X50 + select MSM_SOC_REV_A + bool "QSD8x50A ST1.5" + help + Support for the Qualcomm ST1.5. + +endmenu config MSM_DEBUG_UART int @@ -27,19 +100,10 @@ choice bool "UART3" endchoice -config MACH_HALIBUT - depends on ARCH_MSM - select CPU_V6 - default y - bool "Halibut Board (QCT SURF7201A)" - help - Support for the Qualcomm SURF7201A eval board. +config MSM_SMD_PKG3 + bool -config MACH_TROUT - select CPU_V6 - default y - bool "HTC Dream (aka trout)" - help - Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. +config MSM_SMD + bool endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 91e6f5c95dc1..66677f0acaed 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,9 +1,22 @@ -obj-y += io.o idle.o irq.o timer.o dma.o -obj-y += devices.o obj-y += proc_comm.o +obj-y += io.o idle.o timer.o dma.o obj-y += vreg.o -obj-y += clock.o clock-7x01a.o +obj-y += acpuclock-arm11.o +obj-y += clock.o clock-pcom.o +obj-y += gpio.o -obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o +ifdef CONFIG_MSM_VIC +obj-y += irq-vic.o +else +obj-y += irq.o +endif + +obj-$(CONFIG_ARCH_QSD8X50) += sirc.o +obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o +obj-$(CONFIG_MSM_SMD) += last_radio_log.o + +obj-$(CONFIG_MACH_TROUT) += board-trout.o devices-msm7x00.o +obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o +obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o +obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o -obj-$(CONFIG_MACH_TROUT) += board-dream.o diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c new file mode 100644 index 000000000000..af5e85b91d02 --- /dev/null +++ b/arch/arm/mach-msm/acpuclock-arm11.c @@ -0,0 +1,526 @@ +/* arch/arm/mach-msm/acpuclock.c + * + * MSM architecture clock driver + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat <san@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/mutex.h> +#include <linux/io.h> +#include <mach/board.h> +#include <mach/msm_iomap.h> + +#include "proc_comm.h" +#include "acpuclock.h" + + +#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) +#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) +#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) + +/* + * ARM11 clock configuration for specific ACPU speeds + */ + +#define ACPU_PLL_TCXO -1 +#define ACPU_PLL_0 0 +#define ACPU_PLL_1 1 +#define ACPU_PLL_2 2 +#define ACPU_PLL_3 3 + +#define PERF_SWITCH_DEBUG 0 +#define PERF_SWITCH_STEP_DEBUG 0 + +struct clock_state +{ + struct clkctl_acpu_speed *current_speed; + struct mutex lock; + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; +}; + +static struct clk *ebi1_clk; +static struct clock_state drv_state = { 0 }; + +static void __init acpuclk_init(void); + +/* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ +enum { + VDD_0 = 0, + VDD_1 = 1, + VDD_2 = 2, + VDD_3 = 3, + VDD_4 = 3, + VDD_5 = 3, + VDD_6 = 3, + VDD_7 = 7, + VDD_END +}; + +struct clkctl_acpu_speed { + unsigned int a11clk_khz; + int pll; + unsigned int a11clk_src_sel; + unsigned int a11clk_src_div; + unsigned int ahbclk_khz; + unsigned int ahbclk_div; + int vdd; + unsigned int axiclk_khz; + unsigned long lpj; /* loops_per_jiffy */ +/* Index in acpu_freq_tbl[] for steppings. */ + short down; + short up; +}; + +/* + * ACPU speed table. Complete table is shown but certain speeds are commented + * out to optimized speed switching. Initalize loops_per_jiffy to 0. + * + * Table stepping up/down is optimized for 256mhz jumps while staying on the + * same PLL. + */ +#if (0) +static struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 8 }, + { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 30720, 0, 0, 8 }, + { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 61440, 0, 0, 8 }, + { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 61440, 0, 0, 9 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 8 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 12 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 11 }, + { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 61440, 0, 0, 12 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 12 }, + { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 128000, 0, 0, 12 }, + { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 128000, 0, 6, 13 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 6, 13 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 5, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 11, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; +#else /* Table of freq we currently use. */ +static struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; +#endif + + +#ifdef CONFIG_CPU_FREQ_TABLE +static struct cpufreq_frequency_table freq_table[] = { + { 0, 122880 }, + { 1, 128000 }, + { 2, 245760 }, + { 3, 384000 }, + { 4, 528000 }, + { 5, CPUFREQ_TABLE_END }, +}; +#endif + +static int pc_pll_request(unsigned id, unsigned on) +{ + int res; + on = !!on; + +#if PERF_SWITCH_DEBUG + if (on) + printk(KERN_DEBUG "Enabling PLL %d\n", id); + else + printk(KERN_DEBUG "Disabling PLL %d\n", id); +#endif + + res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); + if (res < 0) + return res; + +#if PERF_SWITCH_DEBUG + if (on) + printk(KERN_DEBUG "PLL %d enabled\n", id); + else + printk(KERN_DEBUG "PLL %d disabled\n", id); +#endif + return res; +} + + +/*---------------------------------------------------------------------------- + * ARM11 'owned' clock control + *---------------------------------------------------------------------------*/ + +unsigned long acpuclk_power_collapse(void) { + int ret = acpuclk_get_rate(); + ret *= 1000; + if (ret > drv_state.power_collapse_khz) + acpuclk_set_rate(drv_state.power_collapse_khz, 1); + return ret; +} + +unsigned long acpuclk_get_wfi_rate(void) +{ + return drv_state.wait_for_irq_khz; +} + +unsigned long acpuclk_wait_for_irq(void) { + int ret = acpuclk_get_rate(); + ret *= 1000; + if (ret > drv_state.wait_for_irq_khz) + acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); + return ret; +} + +static int acpuclk_set_vdd_level(int vdd) +{ + uint32_t current_vdd; + + current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n", + current_vdd, vdd); +#endif + writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR); + udelay(drv_state.vdd_switch_time_us); + if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) { +#if PERF_SWITCH_DEBUG + printk(KERN_ERR "acpuclock: VDD set failed\n"); +#endif + return -EIO; + } + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "acpuclock: VDD switched\n"); +#endif + return 0; +} + +/* Set proper dividers for the given clock speed. */ +static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) { + uint32_t reg_clkctl, reg_clksel, clk_div; + + /* AHB_CLK_DIV */ + clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03; + /* + * If the new clock divider is higher than the previous, then + * program the divider before switching the clock + */ + if (hunt_s->ahbclk_div > clk_div) { + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~(0x3 << 1); + reg_clksel |= (hunt_s->ahbclk_div << 1); + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } + if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) { + /* SRC0 */ + + /* Program clock source */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0x07 << 4); + reg_clkctl |= (hunt_s->a11clk_src_sel << 4); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~0xf; + reg_clkctl |= hunt_s->a11clk_src_div; + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel |= 1; /* CLK_SEL_SRC1NO == SRC1 */ + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } else { + /* SRC1 */ + + /* Program clock source */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0x07 << 12); + reg_clkctl |= (hunt_s->a11clk_src_sel << 12); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0xf << 8); + reg_clkctl |= (hunt_s->a11clk_src_div << 8); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~1; /* CLK_SEL_SRC1NO == SRC0 */ + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } + + /* + * If the new clock divider is lower than the previous, then + * program the divider after switching the clock + */ + if (hunt_s->ahbclk_div < clk_div) { + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~(0x3 << 1); + reg_clksel |= (hunt_s->ahbclk_div << 1); + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } +} + +int acpuclk_set_rate(unsigned long rate, int for_power_collapse) +{ + uint32_t reg_clkctl; + struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; + int rc = 0; + unsigned int plls_enabled = 0, pll; + + strt_s = cur_s = drv_state.current_speed; + + WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n"); + if (cur_s == NULL) + return -ENOENT; + + if (rate == (cur_s->a11clk_khz * 1000)) + return 0; + + for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { + if (tgt_s->a11clk_khz == (rate / 1000)) + break; + } + + if (tgt_s->a11clk_khz == 0) + return -EINVAL; + + /* Choose the highest speed speed at or below 'rate' with same PLL. */ + if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) { + while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll) + tgt_s--; + } + + if (strt_s->pll != ACPU_PLL_TCXO) + plls_enabled |= 1 << strt_s->pll; + + if (!for_power_collapse) { + mutex_lock(&drv_state.lock); + if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { + rc = pc_pll_request(tgt_s->pll, 1); + if (rc < 0) { + pr_err("PLL%d enable failed (%d)\n", + tgt_s->pll, rc); + goto out; + } + plls_enabled |= 1 << tgt_s->pll; + } + /* Increase VDD if needed. */ + if (tgt_s->vdd > cur_s->vdd) { + if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) { + printk(KERN_ERR "Unable to switch ACPU vdd\n"); + goto out; + } + } + } + + /* Set wait states for CPU inbetween frequency changes */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl |= (100 << 16); /* set WT_ST_CNT */ + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + +#if PERF_SWITCH_DEBUG + printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n", + strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000); +#endif + + while (cur_s != tgt_s) { + /* + * Always jump to target freq if within 256mhz, regulardless of + * PLL. If differnece is greater, use the predefinied + * steppings in the table. + */ + int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz)); + if (d > drv_state.max_speed_delta_khz) { + /* Step up or down depending on target vs current. */ + int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ? + cur_s->up : cur_s->down; + if (clk_index < 0) { /* This should not happen. */ + printk(KERN_ERR "cur:%u target: %u\n", + cur_s->a11clk_khz, tgt_s->a11clk_khz); + rc = -EINVAL; + goto out; + } + cur_s = &acpu_freq_tbl[clk_index]; + } else { + cur_s = tgt_s; + } +#if PERF_SWITCH_STEP_DEBUG + printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", + __FUNCTION__, cur_s->a11clk_khz, cur_s->pll); +#endif + if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO + && !(plls_enabled & (1 << cur_s->pll))) { + rc = pc_pll_request(cur_s->pll, 1); + if (rc < 0) { + pr_err("PLL%d enable failed (%d)\n", + cur_s->pll, rc); + goto out; + } + plls_enabled |= 1 << cur_s->pll; + } + + acpuclk_set_div(cur_s); + drv_state.current_speed = cur_s; + /* Re-adjust lpj for the new clock speed. */ + loops_per_jiffy = cur_s->lpj; + udelay(drv_state.acpu_switch_time_us); + } + + /* Nothing else to do for power collapse. */ + if (for_power_collapse) + return 0; + + /* Disable PLLs we are not using anymore. */ + plls_enabled &= ~(1 << tgt_s->pll); + for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++) + if (plls_enabled & (1 << pll)) { + rc = pc_pll_request(pll, 0); + if (rc < 0) { + pr_err("PLL%d disable failed (%d)\n", pll, rc); + goto out; + } + } + + /* Change the AXI bus frequency if we can. */ + if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { + rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + } + + /* Drop VDD level if we can. */ + if (tgt_s->vdd < strt_s->vdd) { + if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) + printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); + } + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); +#endif +out: + if (!for_power_collapse) + mutex_unlock(&drv_state.lock); + return rc; +} + +static void __init acpuclk_init(void) +{ + struct clkctl_acpu_speed *speed; + uint32_t div, sel; + int rc; + + /* + * Determine the rate of ACPU clock + */ + + if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */ + /* CLK_SRC0_SEL */ + sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7; + /* CLK_SRC0_DIV */ + div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f; + } else { + /* CLK_SRC1_SEL */ + sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07; + /* CLK_SRC1_DIV */ + div = readl(A11S_CLK_CNTL_ADDR) & 0x0f; + } + + for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { + if (speed->a11clk_src_sel == sel + && (speed->a11clk_src_div == div)) + break; + } + if (speed->a11clk_khz == 0) { + printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n"); + return; + } + + drv_state.current_speed = speed; + + rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + + printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); +} + +unsigned long acpuclk_get_rate(void) +{ + WARN_ONCE(drv_state.current_speed == NULL, + "acpuclk_get_rate: not initialized\n"); + if (drv_state.current_speed) + return drv_state.current_speed->a11clk_khz; + else + return 0; +} + +uint32_t acpuclk_get_switch_time(void) +{ + return drv_state.acpu_switch_time_us; +} + +/*---------------------------------------------------------------------------- + * Clock driver initialization + *---------------------------------------------------------------------------*/ + +/* Initalize the lpj field in the acpu_freq_tbl. */ +static void __init lpj_init(void) +{ + int i; + const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; + for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, + base_clk->a11clk_khz, + acpu_freq_tbl[i].a11clk_khz); + } +} + +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) +{ + pr_info("acpu_clock_init()\n"); + + ebi1_clk = clk_get(NULL, "ebi1_clk"); + + mutex_init(&drv_state.lock); + drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; + drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; + drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; + drv_state.power_collapse_khz = clkdata->power_collapse_khz; + drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; + acpuclk_init(); + lpj_init(); +#ifdef CONFIG_CPU_FREQ_TABLE + cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); +#endif +} diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h new file mode 100644 index 000000000000..415de2eb9a5e --- /dev/null +++ b/arch/arm/mach-msm/acpuclock.h @@ -0,0 +1,32 @@ +/* arch/arm/mach-msm/acpuclock.h + * + * MSM architecture clock driver header + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat <san@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H +#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H + +int acpuclk_set_rate(unsigned long rate, int for_power_collapse); +unsigned long acpuclk_get_rate(void); +uint32_t acpuclk_get_switch_time(void); +unsigned long acpuclk_wait_for_irq(void); +unsigned long acpuclk_power_collapse(void); +unsigned long acpuclk_get_wfi_rate(void); + + +#endif + diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index e61967dde9a1..7bd72e8f127e 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -26,6 +26,7 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/flash.h> +#include <asm/setup.h> #include <mach/irqs.h> #include <mach/board.h> @@ -77,14 +78,28 @@ static void __init halibut_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); } +static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + mi->bank[0].size = (101*1024*1024); +} + static void __init halibut_map_io(void) { msm_map_common_io(); - msm_clock_init(); + msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif .boot_params = 0x10000100, + .fixup = halibut_fixup, .map_io = halibut_map_io, .init_irq = halibut_init_irq, .init_machine = halibut_init, diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c new file mode 100644 index 000000000000..bcbefdfe7b5e --- /dev/null +++ b/arch/arm/mach-msm/board-mahimahi.c @@ -0,0 +1,87 @@ +/* linux/arch/arm/mach-msm/board-mahimahi.c + * + * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2009 HTC Corporation. + * Author: Dima Zavin <dima@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/setup.h> + +#include <mach/board.h> +#include <mach/hardware.h> +#include <mach/system.h> + +#include "board-mahimahi.h" +#include "devices.h" +#include "proc_comm.h" + +static uint debug_uart; + +module_param_named(debug_uart, debug_uart, uint, 0); + +static struct platform_device *devices[] __initdata = { +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) + &msm_device_uart1, +#endif + &msm_device_uart_dm1, + &msm_device_nand, +}; + +static void __init mahimahi_init(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init mahimahi_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 2; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + mi->bank[0].size = (219*1024*1024); + mi->bank[1].start = MSM_HIGHMEM_BASE; + mi->bank[1].node = PHYS_TO_NID(MSM_HIGHMEM_BASE); + mi->bank[1].size = MSM_HIGHMEM_SIZE; +} + +static void __init mahimahi_map_io(void) +{ + msm_map_common_io(); + msm_clock_init(); +} + +extern struct sys_timer msm_timer; + +MACHINE_START(MAHIMAHI, "mahimahi") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x20000100, + .fixup = mahimahi_fixup, + .map_io = mahimahi_map_io, + .init_irq = msm_init_irq, + .init_machine = mahimahi_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c new file mode 100644 index 000000000000..cccb9f3c9d01 --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/bootmem.h> +#include <linux/power_supply.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> +#include <asm/setup.h> +#ifdef CONFIG_CACHE_L2X0 +#include <asm/hardware/cache-l2x0.h> +#endif + +#include <mach/vreg.h> +#include <mach/mpp.h> +#include <mach/gpio.h> +#include <mach/board.h> +#include <mach/msm_iomap.h> + +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include "devices.h" +#include "socinfo.h" +#include "clock.h" + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x9C004300, + .end = 0x9C0043ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(132), + .end = MSM_GPIO_TO_INT(132), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *devices[] __initdata = { + &msm_device_uart3, + &msm_device_smd, + &msm_device_dmov, + &msm_device_nand, + &smc91x_device, +}; + +extern struct sys_timer msm_timer; + +static void __init msm7x2x_init_irq(void) +{ + msm_init_irq(); +} + +static void __init msm7x2x_init(void) +{ + if (socinfo_init() < 0) + BUG(); + + if (machine_is_msm7x25_ffa() || machine_is_msm7x27_ffa()) { + smc91x_resources[0].start = 0x98000300; + smc91x_resources[0].end = 0x980003ff; + smc91x_resources[1].start = MSM_GPIO_TO_INT(85); + smc91x_resources[1].end = MSM_GPIO_TO_INT(85); + if (gpio_tlmm_config(GPIO_CFG(85, 0, + GPIO_INPUT, + GPIO_PULL_DOWN, + GPIO_2MA), + GPIO_ENABLE)) { + printk(KERN_ERR + "%s: Err: Config GPIO-85 INT\n", + __func__); + } + } + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init msm7x2x_map_io(void) +{ + msm_map_common_io(); + /* Technically dependent on the SoC but using machine_is + * macros since socinfo is not available this early and there + * are plans to restructure the code which will eliminate the + * need for socinfo. + */ + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) + msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27); + + if (machine_is_msm7x25_surf() || machine_is_msm7x25_ffa()) + msm_clock_init(msm_clocks_7x25, msm_num_clocks_7x25); + +#ifdef CONFIG_CACHE_L2X0 + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) { + /* 7x27 has 256KB L2 cache: + 64Kb/Way and 4-Way Associativity; + R/W latency: 3 cycles; + evmon/parity/share disabled. */ + l2x0_init(MSM_L2CC_BASE, 0x00068012, 0xfe000000); + } +#endif +} + +MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x2x_map_io, + .init_irq = msm7x2x_init_irq, + .init_machine = msm7x2x_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c new file mode 100644 index 000000000000..bac1f3c38a3b --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/bootmem.h> +#include <linux/io.h> +#include <linux/smsc911x.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/setup.h> + +#include <mach/gpio.h> +#include <mach/board.h> +#include <mach/memory.h> +#include <mach/msm_iomap.h> +#include <mach/dma.h> + +#include <mach/vreg.h> +#include "devices.h" +#include "proc_comm.h" + +extern struct sys_timer msm_timer; + +#ifdef CONFIG_SERIAL_MSM_CONSOLE +static struct msm_gpio uart2_config_data[] = { + { GPIO_CFG(49, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_RFR"}, + { GPIO_CFG(50, 2, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_CTS"}, + { GPIO_CFG(51, 2, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"}, + { GPIO_CFG(52, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"}, +}; + +static void msm7x30_init_uart2(void) +{ + msm_gpios_request_enable(uart2_config_data, + ARRAY_SIZE(uart2_config_data)); + +} +#endif + +static struct platform_device *devices[] __initdata = { +#if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER) + &msm_device_uart2, +#endif + +}; + +static void __init msm7x30_init_irq(void) +{ + msm_init_irq(); +} + +static void __init msm7x30_init(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +#ifdef CONFIG_SERIAL_MSM_CONSOLE + msm7x30_init_uart2(); +#endif + +} + +static void __init msm7x30_map_io(void) +{ + msm_map_msm7x30_io(); + msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30); +} + +MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c new file mode 100644 index 000000000000..ec4606643d2c --- /dev/null +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -0,0 +1,94 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/bootmem.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/io.h> +#include <asm/setup.h> + +#include <mach/board.h> +#include <mach/irqs.h> +#include <mach/sirc.h> +#include <mach/gpio.h> + +#include "devices.h" + +extern struct sys_timer msm_timer; + +static struct msm_gpio uart3_config_data[] = { + { GPIO_CFG(86, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"}, + { GPIO_CFG(87, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"}, +}; + +static struct platform_device *devices[] __initdata = { + &msm_device_uart3, +}; + +static void msm8x50_init_uart3(void) +{ + msm_gpios_request_enable(uart3_config_data, + ARRAY_SIZE(uart3_config_data)); +} + +static void __init qsd8x50_map_io(void) +{ + msm_map_qsd8x50_io(); + msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); +} + +static void __init qsd8x50_init_irq(void) +{ + msm_init_irq(); + msm_init_sirc(); +} + +static void __init qsd8x50_init(void) +{ + msm8x50_init_uart3(); + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c new file mode 100644 index 000000000000..2bc1b9d5623e --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire.c @@ -0,0 +1,118 @@ +/* linux/arch/arm/mach-msm/board-sapphire.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai <thomas_tsai@htc.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/sysdev.h> + +#include <linux/delay.h> + +#include <asm/gpio.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> +#include <asm/system.h> +#include <mach/system.h> +#include <mach/vreg.h> +#include <mach/board.h> + +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/setup.h> + +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include "gpio_chip.h" +#include "board-sapphire.h" +#include "proc_comm.h" +#include "devices.h" + +void msm_init_irq(void); +void msm_init_gpio(void); + +static struct platform_device *devices[] __initdata = { + &msm_device_smd, + &msm_device_dmov, + &msm_device_nand, + &msm_device_uart1, + &msm_device_uart3, +}; + +extern struct sys_timer msm_timer; + +static void __init sapphire_init_irq(void) +{ + msm_init_irq(); +} + +static void __init sapphire_init(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static struct map_desc sapphire_io_desc[] __initdata = { + { + .virtual = SAPPHIRE_CPLD_BASE, + .pfn = __phys_to_pfn(SAPPHIRE_CPLD_START), + .length = SAPPHIRE_CPLD_SIZE, + .type = MT_DEVICE_NONSHARED + } +}; + +static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + int smi_sz = parse_tag_smi((const struct tag *)tags); + + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + if (smi_sz == 32) { + mi->bank[0].size = (84*1024*1024); + } else if (smi_sz == 64) { + mi->bank[0].size = (101*1024*1024); + } else { + /* Give a default value when not get smi size */ + smi_sz = 64; + mi->bank[0].size = (101*1024*1024); + } +} + +static void __init sapphire_map_io(void) +{ + msm_map_common_io(); + iotable_init(sapphire_io_desc, ARRAY_SIZE(sapphire_io_desc)); + msm_clock_init(); +} + +MACHINE_START(SAPPHIRE, "sapphire") +/* Maintainer: Brian Swetland <swetland@google.com> */ +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = PHYS_OFFSET + 0x100, + .fixup = sapphire_fixup, + .map_io = sapphire_map_io, + .init_irq = sapphire_init_irq, + .init_machine = sapphire_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-dream.c b/arch/arm/mach-msm/board-trout.c index 21afa8513168..dca5a5f062dc 100644 --- a/arch/arm/mach-msm/board-dream.c +++ b/arch/arm/mach-msm/board-trout.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-msm/board-dream.c +/* linux/arch/arm/mach-msm/board-trout.c * * Copyright (C) 2009 Google, Inc. * Author: Brian Swetland <swetland@google.com> @@ -28,7 +28,7 @@ #include <mach/msm_iomap.h> #include "devices.h" -#include "board-dream.h" +#include "board-trout.h" static struct platform_device *devices[] __initdata = { &msm_device_uart3, @@ -78,12 +78,14 @@ static void __init trout_map_io(void) writeb(0x80, TROUT_CPLD_BASE + 0x00); #endif - msm_clock_init(); + msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } MACHINE_START(TROUT, "HTC Dream") +#ifdef CONFIG_MSM_DEBUG_UART .phys_io = MSM_DEBUG_UART_PHYS, .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif .boot_params = 0x10000100, .fixup = trout_fixup, .map_io = trout_map_io, diff --git a/arch/arm/mach-msm/board-dream.h b/arch/arm/mach-msm/board-trout.h index 4f345a5a0a61..4f345a5a0a61 100644 --- a/arch/arm/mach-msm/board-dream.h +++ b/arch/arm/mach-msm/board-trout.h diff --git a/arch/arm/mach-msm/clock-7x01a.c b/arch/arm/mach-msm/clock-7x01a.c deleted file mode 100644 index 62230a3428ee..000000000000 --- a/arch/arm/mach-msm/clock-7x01a.c +++ /dev/null @@ -1,126 +0,0 @@ -/* arch/arm/mach-msm/clock-7x01a.c - * - * Clock tables for MSM7X01A - * - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/platform_device.h> - -#include "clock.h" -#include "devices.h" - -/* clock IDs used by the modem processor */ - -#define ACPU_CLK 0 /* Applications processor clock */ -#define ADM_CLK 1 /* Applications data mover clock */ -#define ADSP_CLK 2 /* ADSP clock */ -#define EBI1_CLK 3 /* External bus interface 1 clock */ -#define EBI2_CLK 4 /* External bus interface 2 clock */ -#define ECODEC_CLK 5 /* External CODEC clock */ -#define EMDH_CLK 6 /* External MDDI host clock */ -#define GP_CLK 7 /* General purpose clock */ -#define GRP_CLK 8 /* Graphics clock */ -#define I2C_CLK 9 /* I2C clock */ -#define ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ -#define ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ -#define IMEM_CLK 12 /* Internal graphics memory clock */ -#define MDC_CLK 13 /* MDDI client clock */ -#define MDP_CLK 14 /* Mobile display processor clock */ -#define PBUS_CLK 15 /* Peripheral bus clock */ -#define PCM_CLK 16 /* PCM clock */ -#define PMDH_CLK 17 /* Primary MDDI host clock */ -#define SDAC_CLK 18 /* Stereo DAC clock */ -#define SDC1_CLK 19 /* Secure Digital Card clocks */ -#define SDC1_PCLK 20 -#define SDC2_CLK 21 -#define SDC2_PCLK 22 -#define SDC3_CLK 23 -#define SDC3_PCLK 24 -#define SDC4_CLK 25 -#define SDC4_PCLK 26 -#define TSIF_CLK 27 /* Transport Stream Interface clocks */ -#define TSIF_REF_CLK 28 -#define TV_DAC_CLK 29 /* TV clocks */ -#define TV_ENC_CLK 30 -#define UART1_CLK 31 /* UART clocks */ -#define UART2_CLK 32 -#define UART3_CLK 33 -#define UART1DM_CLK 34 -#define UART2DM_CLK 35 -#define USB_HS_CLK 36 /* High speed USB core clock */ -#define USB_HS_PCLK 37 /* High speed USB pbus clock */ -#define USB_OTG_CLK 38 /* Full speed USB clock */ -#define VDC_CLK 39 /* Video controller clock */ -#define VFE_CLK 40 /* Camera / Video Front End clock */ -#define VFE_MDC_CLK 41 /* VFE MDDI client clock */ - -#define NR_CLKS 42 - -#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \ - .name = clk_name, \ - .id = clk_id, \ - .flags = clk_flags, \ - .dev = clk_dev, \ - } - -#define OFF CLKFLAG_AUTO_OFF -#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET - -struct clk msm_clocks[] = { - CLOCK("adm_clk", ADM_CLK, NULL, 0), - CLOCK("adsp_clk", ADSP_CLK, NULL, 0), - CLOCK("ebi1_clk", EBI1_CLK, NULL, 0), - CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), - CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), - CLOCK("emdh_clk", EMDH_CLK, NULL, OFF), - CLOCK("gp_clk", GP_CLK, NULL, 0), - CLOCK("grp_clk", GRP_CLK, NULL, OFF), - CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLOCK("imem_clk", IMEM_CLK, NULL, OFF), - CLOCK("mdc_clk", MDC_CLK, NULL, 0), - CLOCK("mdp_clk", MDP_CLK, NULL, OFF), - CLOCK("pbus_clk", PBUS_CLK, NULL, 0), - CLOCK("pcm_clk", PCM_CLK, NULL, 0), - CLOCK("pmdh_clk", PMDH_CLK, NULL, OFF | MINMAX), - CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), - CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLOCK("tsif_clk", TSIF_CLK, NULL, 0), - CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), - CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), - CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), - CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLOCK("uart1dm_clk", UART1DM_CLK, NULL, OFF), - CLOCK("uart2dm_clk", UART2DM_CLK, NULL, 0), - CLOCK("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF), - CLOCK("usb_hs_pclk", USB_HS_PCLK, &msm_device_hsusb.dev, OFF), - CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLOCK("vdc_clk", VDC_CLK, NULL, OFF | MINMAX), - CLOCK("vfe_clk", VFE_CLK, NULL, OFF), - CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), -}; - -unsigned msm_num_clocks = ARRAY_SIZE(msm_clocks); diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h new file mode 100644 index 000000000000..e16f72f32829 --- /dev/null +++ b/arch/arm/mach-msm/clock-7x30.h @@ -0,0 +1,168 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_CLOCK_7X30_H +#define __ARCH_ARM_MACH_MSM_CLOCK_7X30_H + +enum { + L_7X30_NONE_CLK = -1, + L_7X30_ADM_CLK, + L_7X30_I2C_CLK, + L_7X30_I2C_2_CLK, + L_7X30_QUP_I2C_CLK, + L_7X30_UART1DM_CLK, + L_7X30_UART1DM_P_CLK, + L_7X30_UART2DM_CLK, + L_7X30_UART2DM_P_CLK, + L_7X30_EMDH_CLK, + L_7X30_EMDH_P_CLK, + L_7X30_PMDH_CLK, + L_7X30_PMDH_P_CLK, + L_7X30_GRP_2D_CLK, + L_7X30_GRP_2D_P_CLK, + L_7X30_GRP_3D_SRC_CLK, + L_7X30_GRP_3D_CLK, + L_7X30_GRP_3D_P_CLK, + L_7X30_IMEM_CLK, + L_7X30_SDC1_CLK, + L_7X30_SDC1_P_CLK, + L_7X30_SDC2_CLK, + L_7X30_SDC2_P_CLK, + L_7X30_SDC3_CLK, + L_7X30_SDC3_P_CLK, + L_7X30_SDC4_CLK, + L_7X30_SDC4_P_CLK, + L_7X30_MDP_CLK, + L_7X30_MDP_P_CLK, + L_7X30_MDP_LCDC_PCLK_CLK, + L_7X30_MDP_LCDC_PAD_PCLK_CLK, + L_7X30_MDP_VSYNC_CLK, + L_7X30_MI2S_CODEC_RX_M_CLK, + L_7X30_MI2S_CODEC_RX_S_CLK, + L_7X30_MI2S_CODEC_TX_M_CLK, + L_7X30_MI2S_CODEC_TX_S_CLK, + L_7X30_MI2S_M_CLK, + L_7X30_MI2S_S_CLK, + L_7X30_LPA_CODEC_CLK, + L_7X30_LPA_CORE_CLK, + L_7X30_LPA_P_CLK, + L_7X30_MIDI_CLK, + L_7X30_MDC_CLK, + L_7X30_ROTATOR_IMEM_CLK, + L_7X30_ROTATOR_P_CLK, + L_7X30_SDAC_M_CLK, + L_7X30_SDAC_CLK, + L_7X30_UART1_CLK, + L_7X30_UART2_CLK, + L_7X30_UART3_CLK, + L_7X30_TV_CLK, + L_7X30_TV_DAC_CLK, + L_7X30_TV_ENC_CLK, + L_7X30_HDMI_CLK, + L_7X30_TSIF_REF_CLK, + L_7X30_TSIF_P_CLK, + L_7X30_USB_HS_SRC_CLK, + L_7X30_USB_HS_CLK, + L_7X30_USB_HS_CORE_CLK, + L_7X30_USB_HS_P_CLK, + L_7X30_USB_HS2_CLK, + L_7X30_USB_HS2_CORE_CLK, + L_7X30_USB_HS2_P_CLK, + L_7X30_USB_HS3_CLK, + L_7X30_USB_HS3_CORE_CLK, + L_7X30_USB_HS3_P_CLK, + L_7X30_VFE_CLK, + L_7X30_VFE_P_CLK, + L_7X30_VFE_MDC_CLK, + L_7X30_VFE_CAMIF_CLK, + L_7X30_CAMIF_PAD_P_CLK, + L_7X30_CAM_M_CLK, + L_7X30_JPEG_CLK, + L_7X30_JPEG_P_CLK, + L_7X30_VPE_CLK, + L_7X30_MFC_CLK, + L_7X30_MFC_DIV2_CLK, + L_7X30_MFC_P_CLK, + L_7X30_SPI_CLK, + L_7X30_SPI_P_CLK, + L_7X30_CSI0_CLK, + L_7X30_CSI0_VFE_CLK, + L_7X30_CSI0_P_CLK, + L_7X30_CSI1_CLK, + L_7X30_CSI1_VFE_CLK, + L_7X30_CSI1_P_CLK, + L_7X30_GLBL_ROOT_CLK, + + L_7X30_AXI_LI_VG_CLK, + L_7X30_AXI_LI_GRP_CLK, + L_7X30_AXI_LI_JPEG_CLK, + L_7X30_AXI_GRP_2D_CLK, + L_7X30_AXI_MFC_CLK, + L_7X30_AXI_VPE_CLK, + L_7X30_AXI_LI_VFE_CLK, + L_7X30_AXI_LI_APPS_CLK, + L_7X30_AXI_MDP_CLK, + L_7X30_AXI_IMEM_CLK, + L_7X30_AXI_LI_ADSP_A_CLK, + L_7X30_AXI_ROTATOR_CLK, + + L_7X30_NR_CLKS +}; + +struct clk_ops; +extern struct clk_ops clk_ops_7x30; + +struct clk_ops *clk_7x30_is_local(uint32_t id); +int clk_7x30_init(void); + +void pll_enable(uint32_t pll); +void pll_disable(uint32_t pll); + +extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable); + +#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = L_7X30_##clk_id, \ + .remote_id = P_##clk_id, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + .dbg_name = #clk_id, \ + } + +#define CLK_7X30S(clk_name, l_id, r_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = L_7X30_##l_id, \ + .remote_id = P_##r_id, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + .dbg_name = #l_id, \ + } + +#endif + diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c new file mode 100644 index 000000000000..a3b45627eb4a --- /dev/null +++ b/arch/arm/mach-msm/clock-pcom.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/err.h> +#include <linux/ctype.h> +#include <linux/stddef.h> +#include <mach/clk.h> + +#include "proc_comm.h" +#include "clock.h" + +/* + * glue for the proc_comm interface + */ +int pc_clk_enable(unsigned id) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +void pc_clk_disable(unsigned id) +{ + msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); +} + +int pc_clk_reset(unsigned id, enum clk_reset_action action) +{ + int rc; + + if (action == CLK_RESET_ASSERT) + rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_ASSERT, &id, NULL); + else + rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_DEASSERT, &id, NULL); + + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_rate(unsigned id, unsigned rate) +{ + /* The rate _might_ be rounded off to the nearest KHz value by the + * remote function. So a return value of 0 doesn't necessarily mean + * that the exact rate was set successfully. + */ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_min_rate(unsigned id, unsigned rate) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_max_rate(unsigned id, unsigned rate) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_flags(unsigned id, unsigned flags) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +unsigned pc_clk_get_rate(unsigned id) +{ + if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL)) + return 0; + else + return id; +} + +unsigned pc_clk_is_enabled(unsigned id) +{ + if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL)) + return 0; + else + return id; +} + +long pc_clk_round_rate(unsigned id, unsigned rate) +{ + + /* Not really supported; pc_clk_set_rate() does rounding on it's own. */ + return rate; +} + +struct clk_ops clk_ops_pcom = { + .enable = pc_clk_enable, + .disable = pc_clk_disable, + .auto_off = pc_clk_disable, + .reset = pc_clk_reset, + .set_rate = pc_clk_set_rate, + .set_min_rate = pc_clk_set_min_rate, + .set_max_rate = pc_clk_set_max_rate, + .set_flags = pc_clk_set_flags, + .get_rate = pc_clk_get_rate, + .is_enabled = pc_clk_is_enabled, + .round_rate = pc_clk_round_rate, +}; diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h new file mode 100644 index 000000000000..17d027b23501 --- /dev/null +++ b/arch/arm/mach-msm/clock-pcom.h @@ -0,0 +1,153 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H +#define __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H + +/* clock IDs used by the modem processor */ + +#define P_ACPU_CLK 0 /* Applications processor clock */ +#define P_ADM_CLK 1 /* Applications data mover clock */ +#define P_ADSP_CLK 2 /* ADSP clock */ +#define P_EBI1_CLK 3 /* External bus interface 1 clock */ +#define P_EBI2_CLK 4 /* External bus interface 2 clock */ +#define P_ECODEC_CLK 5 /* External CODEC clock */ +#define P_EMDH_CLK 6 /* External MDDI host clock */ +#define P_GP_CLK 7 /* General purpose clock */ +#define P_GRP_3D_CLK 8 /* Graphics clock */ +#define P_I2C_CLK 9 /* I2C clock */ +#define P_ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ +#define P_ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ +#define P_IMEM_CLK 12 /* Internal graphics memory clock */ +#define P_MDC_CLK 13 /* MDDI client clock */ +#define P_MDP_CLK 14 /* Mobile display processor clock */ +#define P_PBUS_CLK 15 /* Peripheral bus clock */ +#define P_PCM_CLK 16 /* PCM clock */ +#define P_PMDH_CLK 17 /* Primary MDDI host clock */ +#define P_SDAC_CLK 18 /* Stereo DAC clock */ +#define P_SDC1_CLK 19 /* Secure Digital Card clocks */ +#define P_SDC1_P_CLK 20 +#define P_SDC2_CLK 21 +#define P_SDC2_P_CLK 22 +#define P_SDC3_CLK 23 +#define P_SDC3_P_CLK 24 +#define P_SDC4_CLK 25 +#define P_SDC4_P_CLK 26 +#define P_TSIF_CLK 27 /* Transport Stream Interface clocks */ +#define P_TSIF_REF_CLK 28 +#define P_TV_DAC_CLK 29 /* TV clocks */ +#define P_TV_ENC_CLK 30 +#define P_UART1_CLK 31 /* UART clocks */ +#define P_UART2_CLK 32 +#define P_UART3_CLK 33 +#define P_UART1DM_CLK 34 +#define P_UART2DM_CLK 35 +#define P_USB_HS_CLK 36 /* High speed USB core clock */ +#define P_USB_HS_P_CLK 37 /* High speed USB pbus clock */ +#define P_USB_OTG_CLK 38 /* Full speed USB clock */ +#define P_VDC_CLK 39 /* Video controller clock */ +#define P_VFE_MDC_CLK 40 /* Camera / Video Front End clock */ +#define P_VFE_CLK 41 /* VFE MDDI client clock */ +#define P_MDP_LCDC_PCLK_CLK 42 +#define P_MDP_LCDC_PAD_PCLK_CLK 43 +#define P_MDP_VSYNC_CLK 44 +#define P_SPI_CLK 45 +#define P_VFE_AXI_CLK 46 +#define P_USB_HS2_CLK 47 /* High speed USB 2 core clock */ +#define P_USB_HS2_P_CLK 48 /* High speed USB 2 pbus clock */ +#define P_USB_HS3_CLK 49 /* High speed USB 3 core clock */ +#define P_USB_HS3_P_CLK 50 /* High speed USB 3 pbus clock */ +#define P_GRP_3D_P_CLK 51 /* Graphics pbus clock */ +#define P_USB_PHY_CLK 52 /* USB PHY clock */ +#define P_USB_HS_CORE_CLK 53 /* High speed USB 1 core clock */ +#define P_USB_HS2_CORE_CLK 54 /* High speed USB 2 core clock */ +#define P_USB_HS3_CORE_CLK 55 /* High speed USB 3 core clock */ +#define P_CAM_M_CLK 56 +#define P_CAMIF_PAD_P_CLK 57 +#define P_GRP_2D_CLK 58 +#define P_GRP_2D_P_CLK 59 +#define P_I2S_CLK 60 +#define P_JPEG_CLK 61 +#define P_JPEG_P_CLK 62 +#define P_LPA_CODEC_CLK 63 +#define P_LPA_CORE_CLK 64 +#define P_LPA_P_CLK 65 +#define P_MDC_IO_CLK 66 +#define P_MDC_P_CLK 67 +#define P_MFC_CLK 68 +#define P_MFC_DIV2_CLK 69 +#define P_MFC_P_CLK 70 +#define P_QUP_I2C_CLK 71 +#define P_ROTATOR_IMEM_CLK 72 +#define P_ROTATOR_P_CLK 73 +#define P_VFE_CAMIF_CLK 74 +#define P_VFE_P_CLK 75 +#define P_VPE_CLK 76 +#define P_I2C_2_CLK 77 +#define P_MI2S_CODEC_RX_S_CLK 78 +#define P_MI2S_CODEC_RX_M_CLK 79 +#define P_MI2S_CODEC_TX_S_CLK 80 +#define P_MI2S_CODEC_TX_M_CLK 81 +#define P_PMDH_P_CLK 82 +#define P_EMDH_P_CLK 83 +#define P_SPI_P_CLK 84 +#define P_TSIF_P_CLK 85 +#define P_MDP_P_CLK 86 +#define P_SDAC_M_CLK 87 +#define P_MI2S_S_CLK 88 +#define P_MI2S_M_CLK 89 +#define P_AXI_ROTATOR_CLK 90 +#define P_HDMI_CLK 91 +#define P_CSI0_CLK 92 +#define P_CSI0_VFE_CLK 93 +#define P_CSI0_P_CLK 94 +#define P_CSI1_CLK 95 +#define P_CSI1_VFE_CLK 96 +#define P_CSI1_P_CLK 97 +#define P_GSBI_CLK 98 +#define P_GSBI_P_CLK 99 + +#define P_NR_CLKS 100 + +struct clk_ops; +extern struct clk_ops clk_ops_pcom; + +int pc_clk_reset(unsigned id, enum clk_reset_action action); + +#define CLK_PCOM(clk_name, clk_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = P_##clk_id, \ + .remote_id = P_##clk_id, \ + .ops = &clk_ops_pcom, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + .dbg_name = #clk_id, \ + } + +#endif diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 3b1ce36f1032..9cb1276ab749 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/clock.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -22,68 +22,27 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/spinlock.h> +#include <linux/debugfs.h> +#include <linux/ctype.h> +#include <linux/pm_qos_params.h> +#include <mach/clk.h> #include "clock.h" #include "proc_comm.h" +#include "clock-7x30.h" static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); static LIST_HEAD(clocks); +struct clk *msm_clocks; +unsigned msm_num_clocks; /* - * glue for the proc_comm interface + * Bitmap of enabled clocks, excluding ACPU which is always + * enabled */ -static inline int pc_clk_enable(unsigned id) -{ - return msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); -} - -static inline void pc_clk_disable(unsigned id) -{ - msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); -} - -static inline int pc_clk_set_rate(unsigned id, unsigned rate) -{ - return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); -} - -static inline int pc_clk_set_min_rate(unsigned id, unsigned rate) -{ - return msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); -} - -static inline int pc_clk_set_max_rate(unsigned id, unsigned rate) -{ - return msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); -} - -static inline int pc_clk_set_flags(unsigned id, unsigned flags) -{ - return msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); -} - -static inline unsigned pc_clk_get_rate(unsigned id) -{ - if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL)) - return 0; - else - return id; -} - -static inline unsigned pc_clk_is_enabled(unsigned id) -{ - if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL)) - return 0; - else - return id; -} - -static inline int pc_pll_request(unsigned id, unsigned on) -{ - on = !!on; - return msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); -} +static DECLARE_BITMAP(clock_map_enabled, NR_CLKS); +static DEFINE_SPINLOCK(clock_map_lock); /* * Standard clock functions defined in include/linux/clk.h @@ -119,8 +78,12 @@ int clk_enable(struct clk *clk) unsigned long flags; spin_lock_irqsave(&clocks_lock, flags); clk->count++; - if (clk->count == 1) - pc_clk_enable(clk->id); + if (clk->count == 1) { + clk->ops->enable(clk->id); + spin_lock(&clock_map_lock); + clock_map_enabled[BIT_WORD(clk->id)] |= BIT_MASK(clk->id); + spin_unlock(&clock_map_lock); + } spin_unlock_irqrestore(&clocks_lock, flags); return 0; } @@ -132,31 +95,54 @@ void clk_disable(struct clk *clk) spin_lock_irqsave(&clocks_lock, flags); BUG_ON(clk->count == 0); clk->count--; - if (clk->count == 0) - pc_clk_disable(clk->id); + if (clk->count == 0) { + clk->ops->disable(clk->id); + spin_lock(&clock_map_lock); + clock_map_enabled[BIT_WORD(clk->id)] &= ~BIT_MASK(clk->id); + spin_unlock(&clock_map_lock); + } spin_unlock_irqrestore(&clocks_lock, flags); } EXPORT_SYMBOL(clk_disable); +int clk_reset(struct clk *clk, enum clk_reset_action action) +{ + if (!clk->ops->reset) + clk->ops->reset = &pc_clk_reset; + return clk->ops->reset(clk->remote_id, action); +} +EXPORT_SYMBOL(clk_reset); + unsigned long clk_get_rate(struct clk *clk) { - return pc_clk_get_rate(clk->id); + return clk->ops->get_rate(clk->id); } EXPORT_SYMBOL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { - int ret; - if (clk->flags & CLKFLAG_USE_MIN_MAX_TO_SET) { - ret = pc_clk_set_max_rate(clk->id, rate); - if (ret) - return ret; - return pc_clk_set_min_rate(clk->id, rate); - } - return pc_clk_set_rate(clk->id, rate); + return clk->ops->set_rate(clk->id, rate); } EXPORT_SYMBOL(clk_set_rate); +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->ops->round_rate(clk->id, rate); +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_min_rate(struct clk *clk, unsigned long rate) +{ + return clk->ops->set_min_rate(clk->id, rate); +} +EXPORT_SYMBOL(clk_set_min_rate); + +int clk_set_max_rate(struct clk *clk, unsigned long rate) +{ + return clk->ops->set_max_rate(clk->id, rate); +} +EXPORT_SYMBOL(clk_set_max_rate); + int clk_set_parent(struct clk *clk, struct clk *parent) { return -ENOSYS; @@ -173,22 +159,153 @@ int clk_set_flags(struct clk *clk, unsigned long flags) { if (clk == NULL || IS_ERR(clk)) return -EINVAL; - return pc_clk_set_flags(clk->id, flags); + return clk->ops->set_flags(clk->id, flags); } EXPORT_SYMBOL(clk_set_flags); +/* EBI1 is the only shared clock that several clients want to vote on as of + * this commit. If this changes in the future, then it might be better to + * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more + * generic to support different clocks. + */ +static struct clk *ebi1_clk; -void __init msm_clock_init(void) +static void __init set_clock_ops(struct clk *clk) +{ + if (!clk->ops) { + clk->ops = &clk_ops_pcom; + clk->id = clk->remote_id; + } +} + +void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks) { unsigned n; spin_lock_init(&clocks_lock); mutex_lock(&clocks_mutex); - for (n = 0; n < msm_num_clocks; n++) + msm_clocks = clock_tbl; + msm_num_clocks = num_clocks; + for (n = 0; n < msm_num_clocks; n++) { + set_clock_ops(&msm_clocks[n]); list_add_tail(&msm_clocks[n].list, &clocks); + } mutex_unlock(&clocks_mutex); + + ebi1_clk = clk_get(NULL, "ebi1_clk"); + BUG_ON(ebi1_clk == NULL); + +} + +#if defined(CONFIG_DEBUG_FS) +static struct clk *msm_clock_get_nth(unsigned index) +{ + if (index < msm_num_clocks) + return msm_clocks + index; + else + return 0; +} + +static int clock_debug_rate_set(void *data, u64 val) +{ + struct clk *clock = data; + int ret; + + /* Only increases to max rate will succeed, but that's actually good + * for debugging purposes. So we don't check for error. */ + if (clock->flags & CLK_MAX) + clk_set_max_rate(clock, val); + if (clock->flags & CLK_MIN) + ret = clk_set_min_rate(clock, val); + else + ret = clk_set_rate(clock, val); + if (ret != 0) + printk(KERN_ERR "clk_set%s_rate failed (%d)\n", + (clock->flags & CLK_MIN) ? "_min" : "", ret); + return ret; +} + +static int clock_debug_rate_get(void *data, u64 *val) +{ + struct clk *clock = data; + *val = clk_get_rate(clock); + return 0; +} + +static int clock_debug_enable_set(void *data, u64 val) +{ + struct clk *clock = data; + int rc = 0; + + if (val) + rc = clock->ops->enable(clock->id); + else + clock->ops->disable(clock->id); + + return rc; } +static int clock_debug_enable_get(void *data, u64 *val) +{ + struct clk *clock = data; + + *val = clock->ops->is_enabled(clock->id); + + return 0; +} + +static int clock_debug_local_get(void *data, u64 *val) +{ + struct clk *clock = data; + + *val = clock->ops != &clk_ops_pcom; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get, + clock_debug_rate_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get, + clock_debug_enable_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get, + NULL, "%llu\n"); + +static int __init clock_debug_init(void) +{ + struct dentry *dent_rate, *dent_enable, *dent_local; + struct clk *clock; + unsigned n = 0; + char temp[50], *ptr; + + dent_rate = debugfs_create_dir("clk_rate", 0); + if (IS_ERR(dent_rate)) + return PTR_ERR(dent_rate); + + dent_enable = debugfs_create_dir("clk_enable", 0); + if (IS_ERR(dent_enable)) + return PTR_ERR(dent_enable); + + dent_local = debugfs_create_dir("clk_local", NULL); + if (IS_ERR(dent_local)) + return PTR_ERR(dent_local); + + while ((clock = msm_clock_get_nth(n++)) != 0) { + strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1); + for (ptr = temp; *ptr; ptr++) + *ptr = tolower(*ptr); + debugfs_create_file(temp, 0644, dent_rate, + clock, &clock_rate_fops); + debugfs_create_file(temp, 0644, dent_enable, + clock, &clock_enable_fops); + debugfs_create_file(temp, S_IRUGO, dent_local, + clock, &clock_local_fops); + } + return 0; +} + +device_initcall(clock_debug_init); +#endif + /* The bootloader and/or AMSS may have left various clocks enabled. * Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have * not been explicitly enabled by a clk_enable() call. @@ -205,7 +322,7 @@ static int __init clock_late_init(void) spin_lock_irqsave(&clocks_lock, flags); if (!clk->count) { count++; - pc_clk_disable(clk->id); + clk->ops->auto_off(clk->id); } spin_unlock_irqrestore(&clocks_lock, flags); } @@ -216,3 +333,4 @@ static int __init clock_late_init(void) } late_initcall(clock_late_init); + diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index f875e1544e5f..c270b552ed13 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/clock.h * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -18,6 +18,10 @@ #define __ARCH_ARM_MACH_MSM_CLOCK_H #include <linux/list.h> +#include <mach/clk.h> + +#include "clock-pcom.h" +#include "clock-7x30.h" #define CLKFLAG_INVERT 0x00000001 #define CLKFLAG_NOINVERT 0x00000002 @@ -25,14 +29,32 @@ #define CLKFLAG_NORESET 0x00000008 #define CLK_FIRST_AVAILABLE_FLAG 0x00000100 -#define CLKFLAG_USE_MIN_MAX_TO_SET 0x00000200 -#define CLKFLAG_AUTO_OFF 0x00000400 +#define CLKFLAG_AUTO_OFF 0x00000200 +#define CLKFLAG_MIN 0x00000400 +#define CLKFLAG_MAX 0x00000800 + +struct clk_ops { + int (*enable)(unsigned id); + void (*disable)(unsigned id); + void (*auto_off)(unsigned id); + int (*reset)(unsigned id, enum clk_reset_action action); + int (*set_rate)(unsigned id, unsigned rate); + int (*set_min_rate)(unsigned id, unsigned rate); + int (*set_max_rate)(unsigned id, unsigned rate); + int (*set_flags)(unsigned id, unsigned flags); + unsigned (*get_rate)(unsigned id); + unsigned (*is_enabled)(unsigned id); + long (*round_rate)(unsigned id, unsigned rate); +}; struct clk { uint32_t id; + uint32_t remote_id; uint32_t count; uint32_t flags; const char *name; + struct clk_ops *ops; + const char *dbg_name; struct list_head list; struct device *dev; }; @@ -41,8 +63,47 @@ struct clk { #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) -extern struct clk msm_clocks[]; -extern unsigned msm_num_clocks; +#ifdef CONFIG_DEBUG_FS +#define CLOCK_DBG_NAME(x) .dbg_name = x, +#else +#define CLOCK_DBG_NAME(x) +#endif + +#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = clk_id, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + CLOCK_DBG_NAME(#clk_id) \ + } + +#define OFF CLKFLAG_AUTO_OFF +#define CLK_MIN CLKFLAG_MIN +#define CLK_MAX CLKFLAG_MAX +#define CLK_MINMAX (CLK_MIN | CLK_MAX) +#define NR_CLKS P_NR_CLKS + +enum { + PLL_0 = 0, + PLL_1, + PLL_2, + PLL_3, + PLL_4, + PLL_5, + PLL_6, + NUM_PLL +}; + +enum clkvote_client { + CLKVOTE_ACPUCLK = 0, + CLKVOTE_PMQOS, + CLKVOTE_MAX, +}; + +int msm_clock_require_tcxo(unsigned long *reason, int nbits); +int msm_clock_get_name(uint32_t id, char *name, uint32_t size); +int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate); +unsigned long clk_get_max_axi_khz(void); #endif diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices-msm7x00.c index 31b6b30e98bf..fde9d8f69f10 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices-msm7x00.c @@ -24,6 +24,10 @@ #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> + +#include "clock.h" +#include <mach/mmc.h> + static struct resource resources_uart1[] = { { .start = INT_UART1, @@ -163,8 +167,19 @@ static struct resource resources_sdc1[] = { }, { .start = INT_SDC1_0, + .end = INT_SDC1_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC1_1, .end = INT_SDC1_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -181,8 +196,19 @@ static struct resource resources_sdc2[] = { }, { .start = INT_SDC2_0, + .end = INT_SDC2_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC2_1, .end = INT_SDC2_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -199,8 +225,19 @@ static struct resource resources_sdc3[] = { }, { .start = INT_SDC3_0, + .end = INT_SDC3_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC3_1, .end = INT_SDC3_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -217,8 +254,19 @@ static struct resource resources_sdc4[] = { }, { .start = INT_SDC4_0, + .end = INT_SDC4_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC4_1, .end = INT_SDC4_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -266,3 +314,80 @@ struct platform_device msm_device_sdc4 = { .coherent_dma_mask = 0xffffffff, }, }; + +static struct platform_device *msm_sdcc_devices[] __initdata = { + &msm_device_sdc1, + &msm_device_sdc2, + &msm_device_sdc3, + &msm_device_sdc4, +}; + +int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat, + unsigned int stat_irq, unsigned long stat_irq_flags) +{ + struct platform_device *pdev; + struct resource *res; + + if (controller < 1 || controller > 4) + return -EINVAL; + + pdev = msm_sdcc_devices[controller-1]; + pdev->dev.platform_data = plat; + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); + if (!res) + return -EINVAL; + else if (stat_irq) { + res->start = res->end = stat_irq; + res->flags &= ~IORESOURCE_DISABLED; + res->flags |= stat_irq_flags; + } + + return platform_device_register(pdev); +} + +struct clk msm_clocks_7x01a[] = { + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, 0), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_3D_CLK, NULL, OFF), + CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, 0), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("pmdh_clk", PMDH_CLK, NULL, OFF ), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_pclk", SDC1_P_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_pclk", SDC2_P_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_pclk", SDC3_P_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("sdc_pclk", SDC4_P_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0), + CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("uart1dm_clk", UART1DM_CLK, NULL, OFF), + CLK_PCOM("uart2dm_clk", UART2DM_CLK, NULL, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, &msm_device_hsusb.dev, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF ), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), +}; + +unsigned msm_num_clocks_7x01a = ARRAY_SIZE(msm_clocks_7x01a); diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c new file mode 100644 index 000000000000..b449e8ad2904 --- /dev/null +++ b/arch/arm/mach-msm/devices-msm7x30.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/dma-mapping.h> +#include <mach/irqs.h> +#include <mach/msm_iomap.h> +#include <mach/dma.h> +#include <mach/board.h> + +#include "devices.h" +#include "smd_private.h" + +#include <asm/mach/flash.h> + +#include "clock-pcom.h" + +#include <mach/mmc.h> + +static struct resource resources_uart2[] = { + { + .start = INT_UART2, + .end = INT_UART2, + .flags = IORESOURCE_IRQ, + }, + { + .start = MSM_UART2_PHYS, + .end = MSM_UART2_PHYS + MSM_UART2_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device msm_device_uart2 = { + .name = "msm_serial", + .id = 1, + .num_resources = ARRAY_SIZE(resources_uart2), + .resource = resources_uart2, +}; + +struct clk msm_clocks_7x30[] = { + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("cam_m_clk", CAM_M_CLK, NULL, 0), + CLK_PCOM("camif_pad_pclk", CAMIF_PAD_P_CLK, NULL, OFF), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("emdh_pclk", EMDH_P_CLK, NULL, OFF), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_2d_clk", GRP_2D_CLK, NULL, 0), + CLK_PCOM("grp_2d_pclk", GRP_2D_P_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_3D_CLK, NULL, 0), + CLK_PCOM("grp_pclk", GRP_3D_P_CLK, NULL, 0), + CLK_7X30S("grp_src_clk", GRP_3D_SRC_CLK, GRP_3D_CLK, NULL, 0), + CLK_PCOM("hdmi_clk", HDMI_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("jpeg_clk", JPEG_CLK, NULL, OFF), + CLK_PCOM("jpeg_pclk", JPEG_P_CLK, NULL, OFF), + CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), + CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), + CLK_PCOM("lpa_pclk", LPA_P_CLK, NULL, 0), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("mddi_pclk", PMDH_P_CLK, NULL, 0), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_pclk", MDP_P_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("mfc_clk", MFC_CLK, NULL, 0), + CLK_PCOM("mfc_div2_clk", MFC_DIV2_CLK, NULL, 0), + CLK_PCOM("mfc_pclk", MFC_P_CLK, NULL, 0), + CLK_PCOM("mi2s_m_clk", MI2S_M_CLK, NULL, 0), + CLK_PCOM("mi2s_s_clk", MI2S_S_CLK, NULL, 0), + CLK_PCOM("mi2s_codec_rx_m_clk", MI2S_CODEC_RX_M_CLK, NULL, 0), + CLK_PCOM("mi2s_codec_rx_s_clk", MI2S_CODEC_RX_S_CLK, NULL, 0), + CLK_PCOM("mi2s_codec_tx_m_clk", MI2S_CODEC_TX_M_CLK, NULL, 0), + CLK_PCOM("mi2s_codec_tx_s_clk", MI2S_CODEC_TX_S_CLK, NULL, 0), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("rotator_clk", AXI_ROTATOR_CLK, NULL, 0), + CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, OFF), + CLK_PCOM("rotator_pclk", ROTATOR_P_CLK, NULL, OFF), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("spi_clk", SPI_CLK, NULL, 0), + CLK_PCOM("spi_pclk", SPI_P_CLK, NULL, 0), + CLK_7X30S("tv_src_clk", TV_CLK, TV_ENC_CLK, NULL, 0), + CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, NULL, OFF), + CLK_PCOM("usb_hs_core_clk", USB_HS_CORE_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_clk", USB_HS2_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_pclk", USB_HS2_P_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_core_clk", USB_HS2_CORE_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_clk", USB_HS3_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_pclk", USB_HS3_P_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_core_clk", USB_HS3_CORE_CLK, NULL, OFF), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_camif_clk", VFE_CAMIF_CLK, NULL, 0), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, 0), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, 0), + CLK_PCOM("vfe_pclk", VFE_P_CLK, NULL, OFF), + CLK_PCOM("vpe_clk", VPE_CLK, NULL, 0), + + /* 7x30 v2 hardware only. */ + CLK_PCOM("csi_clk", CSI0_CLK, NULL, 0), + CLK_PCOM("csi_pclk", CSI0_P_CLK, NULL, 0), + CLK_PCOM("csi_vfe_clk", CSI0_VFE_CLK, NULL, 0), +}; + +unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30); + diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c new file mode 100644 index 000000000000..4d4a50785e34 --- /dev/null +++ b/arch/arm/mach-msm/devices-qsd8x50.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/dma-mapping.h> +#include <mach/irqs.h> +#include <mach/msm_iomap.h> +#include <mach/dma.h> +#include <mach/board.h> + +#include "devices.h" + +#include <asm/mach/flash.h> + +#include <mach/mmc.h> + +static struct resource resources_uart3[] = { + { + .start = INT_UART3, + .end = INT_UART3, + .flags = IORESOURCE_IRQ, + }, + { + .start = MSM_UART3_PHYS, + .end = MSM_UART3_PHYS + MSM_UART3_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device msm_device_uart3 = { + .name = "msm_serial", + .id = 2, + .num_resources = ARRAY_SIZE(resources_uart3), + .resource = resources_uart3, +}; + +struct clk msm_clocks_8x50[] = { + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_3D_CLK, NULL, 0), + CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("spi_clk", SPI_CLK, NULL, 0), + CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0), + CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, NULL, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("vfe_axi_clk", VFE_AXI_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_clk", USB_HS2_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_pclk", USB_HS2_P_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_clk", USB_HS3_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_pclk", USB_HS3_P_CLK, NULL, OFF), + CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0), +}; + +unsigned msm_num_clocks_8x50 = ARRAY_SIZE(msm_clocks_8x50); + diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index 0744c4a27d6a..568443e76423 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -16,6 +16,8 @@ #ifndef __ARCH_ARM_MACH_MSM_DEVICES_H #define __ARCH_ARM_MACH_MSM_DEVICES_H +#include "clock.h" + extern struct platform_device msm_device_uart1; extern struct platform_device msm_device_uart2; extern struct platform_device msm_device_uart3; @@ -33,4 +35,13 @@ extern struct platform_device msm_device_smd; extern struct platform_device msm_device_nand; +extern struct clk msm_clocks_7x01a[]; +extern unsigned msm_num_clocks_7x01a; + +extern struct clk msm_clocks_7x30[]; +extern unsigned msm_num_clocks_7x30; + +extern struct clk msm_clocks_8x50[]; +extern unsigned msm_num_clocks_8x50; + #endif diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index f5420f9585c5..3d725ae518e4 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -13,6 +13,8 @@ * */ +#include <linux/clk.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/interrupt.h> #include <mach/dma.h> @@ -26,6 +28,7 @@ enum { }; static DEFINE_SPINLOCK(msm_dmov_lock); +static struct clk *msm_dmov_clk; static unsigned int channel_active; static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; @@ -54,6 +57,9 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) unsigned int status; spin_lock_irqsave(&msm_dmov_lock, irq_flags); + if (!channel_active) + clk_enable(msm_dmov_clk); + dsb(); status = readl(DMOV_STATUS(id)); if (list_empty(&ready_commands[id]) && (status & DMOV_STATUS_CMD_PTR_RDY)) { @@ -70,6 +76,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) channel_active |= 1U << id; writel(cmd->cmdptr, DMOV_CMD_PTR(id)); } else { + if (!channel_active) + clk_disable(msm_dmov_clk); if (list_empty(&active_commands[id])) PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); @@ -165,6 +173,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) "for %p, result %x\n", id, cmd, ch_result); if (cmd) { list_del(&cmd->list); + dsb(); cmd->complete_func(cmd, ch_result, NULL); } } @@ -181,6 +190,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); + dsb(); cmd->complete_func(cmd, ch_result, &errdata); } } @@ -198,6 +208,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); if (cmd) { list_del(&cmd->list); + dsb(); cmd->complete_func(cmd, ch_result, &errdata); } /* this does not seem to work, once we get an error */ @@ -219,8 +230,10 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); } - if (!channel_active) - disable_irq(INT_ADM_AARM); + if (!channel_active) { + disable_irq_nosync(INT_ADM_AARM); + clk_disable(msm_dmov_clk); + } spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); return IRQ_HANDLED; @@ -230,11 +243,17 @@ static int __init msm_init_datamover(void) { int i; int ret; + struct clk *clk; + for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { INIT_LIST_HEAD(&ready_commands[i]); INIT_LIST_HEAD(&active_commands[i]); writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); } + clk = clk_get(NULL, "adm_clk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + msm_dmov_clk = clk; ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); if (ret) return ret; diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c new file mode 100644 index 000000000000..bc32c845c7b0 --- /dev/null +++ b/arch/arm/mach-msm/gpio.c @@ -0,0 +1,85 @@ +/* linux/arch/arm/mach-msm/gpio.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <mach/gpio.h> +#include "proc_comm.h" + +int gpio_tlmm_config(unsigned config, unsigned disable) +{ + return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable); +} +EXPORT_SYMBOL(gpio_tlmm_config); + +int msm_gpios_enable(const struct msm_gpio *table, int size) +{ + int rc; + int i; + const struct msm_gpio *g; + for (i = 0; i < size; i++) { + g = table + i; + rc = gpio_tlmm_config(g->gpio_cfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config(0x%08x, GPIO_ENABLE)" + " <%s> failed: %d\n", + g->gpio_cfg, g->label ?: "?", rc); + pr_err("pin %d func %d dir %d pull %d drvstr %d\n", + GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg), + GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg), + GPIO_DRVSTR(g->gpio_cfg)); + goto err; + } + } + return 0; +err: + msm_gpios_disable(table, i); + return rc; +} +EXPORT_SYMBOL(msm_gpios_enable); + +void msm_gpios_disable(const struct msm_gpio *table, int size) +{ + int rc; + int i; + const struct msm_gpio *g; + for (i = size-1; i >= 0; i--) { + g = table + i; + rc = gpio_tlmm_config(g->gpio_cfg, GPIO_DISABLE); + if (rc) { + pr_err("gpio_tlmm_config(0x%08x, GPIO_DISABLE)" + " <%s> failed: %d\n", + g->gpio_cfg, g->label ?: "?", rc); + pr_err("pin %d func %d dir %d pull %d drvstr %d\n", + GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg), + GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg), + GPIO_DRVSTR(g->gpio_cfg)); + } + } +} +EXPORT_SYMBOL(msm_gpios_disable); + +int msm_gpios_request_enable(const struct msm_gpio *table, int size) +{ + int rc = msm_gpios_enable(table, size); + return rc; +} +EXPORT_SYMBOL(msm_gpios_request_enable); + +void msm_gpios_disable_free(const struct msm_gpio *table, int size) +{ + msm_gpios_disable(table, size); +} +EXPORT_SYMBOL(msm_gpios_disable_free); diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 264d62e519f3..e302fbdc439b 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -21,18 +21,24 @@ /* platform device data structures */ -struct msm_mddi_platform_data +struct msm_acpu_clock_platform_data { - void (*panel_power)(int on); - unsigned has_vsync_irq:1; + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; }; +struct clk; + /* common init routines for use by arch/arm/mach-msm/board-*.c */ void __init msm_add_devices(void); void __init msm_map_common_io(void); void __init msm_init_irq(void); void __init msm_init_gpio(void); -void __init msm_clock_init(void); +void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks); +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *); #endif diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h new file mode 100644 index 000000000000..c05ca40478c7 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __MACH_CLK_H +#define __MACH_CLK_H + +/* Magic rate value for use with PM QOS to request the board's maximum + * supported AXI rate. PM QOS will only pass positive s32 rate values + * through to the clock driver, so INT_MAX is used. + */ +#define MSM_AXI_MAX_FREQ LONG_MAX + +enum clk_reset_action { + CLK_RESET_DEASSERT = 0, + CLK_RESET_ASSERT = 1 +}; + +struct clk; + +/* Rate is minimum clock rate in Hz */ +int clk_set_min_rate(struct clk *clk, unsigned long rate); + +/* Rate is maximum clock rate in Hz */ +int clk_set_max_rate(struct clk *clk, unsigned long rate); + +/* Assert/Deassert reset to a hardware block associated with a clock */ +int clk_reset(struct clk *clk, enum clk_reset_action action); + +/* Set clock-specific configuration parameters */ +int clk_set_flags(struct clk *clk, unsigned long flags); + +#endif diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index 5ab5bdffab07..04c51cc04f31 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -41,40 +41,42 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); #define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2)) #define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2)) -/* only security domain 3 is available to the ARM11 - * SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM - */ +#if defined(CONFIG_ARCH_MSM7X30) +#define DMOV_SD_AARM DMOV_SD2 +#else +#define DMOV_SD_AARM DMOV_SD3 +#endif -#define DMOV_CMD_PTR(ch) DMOV_SD3(0x000, ch) +#define DMOV_CMD_PTR(ch) DMOV_SD_AARM(0x000, ch) #define DMOV_CMD_LIST (0 << 29) /* does not work */ #define DMOV_CMD_PTR_LIST (1 << 29) /* works */ #define DMOV_CMD_INPUT_CFG (2 << 29) /* untested */ #define DMOV_CMD_OUTPUT_CFG (3 << 29) /* untested */ #define DMOV_CMD_ADDR(addr) ((addr) >> 3) -#define DMOV_RSLT(ch) DMOV_SD3(0x040, ch) +#define DMOV_RSLT(ch) DMOV_SD_AARM(0x040, ch) #define DMOV_RSLT_VALID (1 << 31) /* 0 == host has empties result fifo */ #define DMOV_RSLT_ERROR (1 << 3) #define DMOV_RSLT_FLUSH (1 << 2) #define DMOV_RSLT_DONE (1 << 1) /* top pointer done */ #define DMOV_RSLT_USER (1 << 0) /* command with FR force result */ -#define DMOV_FLUSH0(ch) DMOV_SD3(0x080, ch) -#define DMOV_FLUSH1(ch) DMOV_SD3(0x0C0, ch) -#define DMOV_FLUSH2(ch) DMOV_SD3(0x100, ch) -#define DMOV_FLUSH3(ch) DMOV_SD3(0x140, ch) -#define DMOV_FLUSH4(ch) DMOV_SD3(0x180, ch) -#define DMOV_FLUSH5(ch) DMOV_SD3(0x1C0, ch) +#define DMOV_FLUSH0(ch) DMOV_SD_AARM(0x080, ch) +#define DMOV_FLUSH1(ch) DMOV_SD_AARM(0x0C0, ch) +#define DMOV_FLUSH2(ch) DMOV_SD_AARM(0x100, ch) +#define DMOV_FLUSH3(ch) DMOV_SD_AARM(0x140, ch) +#define DMOV_FLUSH4(ch) DMOV_SD_AARM(0x180, ch) +#define DMOV_FLUSH5(ch) DMOV_SD_AARM(0x1C0, ch) -#define DMOV_STATUS(ch) DMOV_SD3(0x200, ch) +#define DMOV_STATUS(ch) DMOV_SD_AARM(0x200, ch) #define DMOV_STATUS_RSLT_COUNT(n) (((n) >> 29)) #define DMOV_STATUS_CMD_COUNT(n) (((n) >> 27) & 3) #define DMOV_STATUS_RSLT_VALID (1 << 1) #define DMOV_STATUS_CMD_PTR_RDY (1 << 0) -#define DMOV_ISR DMOV_SD3(0x380, 0) - -#define DMOV_CONFIG(ch) DMOV_SD3(0x300, ch) +#define DMOV_ISR DMOV_SD_AARM(0x380, 0) + +#define DMOV_CONFIG(ch) DMOV_SD_AARM(0x300, ch) #define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2) #define DMOV_CONFIG_FORCE_FLUSH_RSLT (1 << 1) #define DMOV_CONFIG_IRQ_EN (1 << 0) diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h new file mode 100644 index 000000000000..262b441b4374 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __ASM_ARCH_MSM_GPIO_H +#define __ASM_ARCH_MSM_GPIO_H + +/** + * struct msm_gpio - GPIO pin description + * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config() + * @label - textual label + * + * Usually, GPIO's are operated by sets. + * This struct accumulate all GPIO information in single source + * and facilitete group operations provided by msm_gpios_xxx() + */ +struct msm_gpio { + u32 gpio_cfg; + const char *label; +}; + +/** + * msm_gpios_request_enable() - request and enable set of GPIOs + * + * Request and configure set of GPIO's + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_request_enable(const struct msm_gpio *table, int size); + +/** + * msm_gpios_disable_free() - disable and free set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_disable_free(const struct msm_gpio *table, int size); + +/** + * msm_gpios_request() - request set of GPIOs + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_request(const struct msm_gpio *table, int size); + +/** + * msm_gpios_free() - free set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_free(const struct msm_gpio *table, int size); + +/** + * msm_gpios_enable() - enable set of GPIOs + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_enable(const struct msm_gpio *table, int size); + +/** + * msm_gpios_disable() - disable set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_disable(const struct msm_gpio *table, int size); + +/* GPIO TLMM (Top Level Multiplexing) Definitions */ + +/* GPIO TLMM: Function -- GPIO specific */ + +/* GPIO TLMM: Direction */ +enum { + GPIO_INPUT, + GPIO_OUTPUT, +}; + +/* GPIO TLMM: Pullup/Pulldown */ +enum { + GPIO_NO_PULL, + GPIO_PULL_DOWN, + GPIO_KEEPER, + GPIO_PULL_UP, +}; + +/* GPIO TLMM: Drive Strength */ +enum { + GPIO_2MA, + GPIO_4MA, + GPIO_6MA, + GPIO_8MA, + GPIO_10MA, + GPIO_12MA, + GPIO_14MA, + GPIO_16MA, +}; + +enum { + GPIO_ENABLE, + GPIO_DISABLE, +}; + +#define GPIO_CFG(gpio, func, dir, pull, drvstr) \ + ((((gpio) & 0x3FF) << 4) | \ + ((func) & 0xf) | \ + (((dir) & 0x1) << 14) | \ + (((pull) & 0x3) << 15) | \ + (((drvstr) & 0xF) << 17)) + +/** + * extract GPIO pin from bit-field used for gpio_tlmm_config + */ +#define GPIO_PIN(gpio_cfg) (((gpio_cfg) >> 4) & 0x3ff) +#define GPIO_FUNC(gpio_cfg) (((gpio_cfg) >> 0) & 0xf) +#define GPIO_DIR(gpio_cfg) (((gpio_cfg) >> 14) & 0x1) +#define GPIO_PULL(gpio_cfg) (((gpio_cfg) >> 15) & 0x3) +#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf) + +int gpio_tlmm_config(unsigned config, unsigned disable); + +#endif /* __ASM_ARCH_MSM_GPIO_H */ diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h index aab964591db4..c35b29f9ac0f 100644 --- a/arch/arm/mach-msm/include/mach/io.h +++ b/arch/arm/mach-msm/include/mach/io.h @@ -26,4 +26,9 @@ void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int m #define __io(a) __typesafe_io(a) #define __mem_pci(a) (a) +void msm_map_qsd8x50_io(void); +void msm_map_msm7x30_io(void); + +extern unsigned int msm_shared_ram_phys; + #endif diff --git a/arch/arm/mach-msm/include/mach/irqs-7x00.h b/arch/arm/mach-msm/include/mach/irqs-7x00.h new file mode 100644 index 000000000000..f1fe70612fe9 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/irqs-7x00.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland <swetland@google.com> + */ + +#ifndef __ASM_ARCH_MSM_IRQS_7X00_H +#define __ASM_ARCH_MSM_IRQS_7X00_H + +/* MSM ARM11 Interrupt Numbers */ +/* See 80-VE113-1 A, pp219-221 */ + +#define INT_A9_M2A_0 0 +#define INT_A9_M2A_1 1 +#define INT_A9_M2A_2 2 +#define INT_A9_M2A_3 3 +#define INT_A9_M2A_4 4 +#define INT_A9_M2A_5 5 +#define INT_A9_M2A_6 6 +#define INT_GP_TIMER_EXP 7 +#define INT_DEBUG_TIMER_EXP 8 +#define INT_UART1 9 +#define INT_UART2 10 +#define INT_UART3 11 +#define INT_UART1_RX 12 +#define INT_UART2_RX 13 +#define INT_UART3_RX 14 +#define INT_USB_OTG 15 +#define INT_MDDI_PRI 16 +#define INT_MDDI_EXT 17 +#define INT_MDDI_CLIENT 18 +#define INT_MDP 19 +#define INT_GRAPHICS 20 +#define INT_ADM_AARM 21 +#define INT_ADSP_A11 22 +#define INT_ADSP_A9_A11 23 +#define INT_SDC1_0 24 +#define INT_SDC1_1 25 +#define INT_SDC2_0 26 +#define INT_SDC2_1 27 +#define INT_KEYSENSE 28 +#define INT_TCHSCRN_SSBI 29 +#define INT_TCHSCRN1 30 +#define INT_TCHSCRN2 31 + +#define INT_GPIO_GROUP1 (32 + 0) +#define INT_GPIO_GROUP2 (32 + 1) +#define INT_PWB_I2C (32 + 2) +#define INT_SOFTRESET (32 + 3) +#define INT_NAND_WR_ER_DONE (32 + 4) +#define INT_NAND_OP_DONE (32 + 5) +#define INT_PBUS_ARM11 (32 + 6) +#define INT_AXI_MPU_SMI (32 + 7) +#define INT_AXI_MPU_EBI1 (32 + 8) +#define INT_AD_HSSD (32 + 9) +#define INT_ARM11_PMU (32 + 10) +#define INT_ARM11_DMA (32 + 11) +#define INT_TSIF_IRQ (32 + 12) +#define INT_UART1DM_IRQ (32 + 13) +#define INT_UART1DM_RX (32 + 14) +#define INT_USB_HS (32 + 15) +#define INT_SDC3_0 (32 + 16) +#define INT_SDC3_1 (32 + 17) +#define INT_SDC4_0 (32 + 18) +#define INT_SDC4_1 (32 + 19) +#define INT_UART2DM_RX (32 + 20) +#define INT_UART2DM_IRQ (32 + 21) + +/* 22-31 are reserved */ + +#define NR_MSM_IRQS 64 +#define NR_GPIO_IRQS 122 +#define NR_BOARD_IRQS 64 + +#endif diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h new file mode 100644 index 000000000000..67c5396514fe --- /dev/null +++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h @@ -0,0 +1,170 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM_ARCH_MSM_IRQS_7X30_H +#define __ASM_ARCH_MSM_IRQS_7X30_H + +/* MSM ACPU Interrupt Numbers */ + +#define INT_DEBUG_TIMER_EXP 0 +#define INT_GPT0_TIMER_EXP 1 +#define INT_GPT1_TIMER_EXP 2 +#define INT_WDT0_ACCSCSSBARK 3 +#define INT_WDT1_ACCSCSSBARK 4 +#define INT_AVS_SVIC 5 +#define INT_AVS_SVIC_SW_DONE 6 +#define INT_SC_DBG_RX_FULL 7 +#define INT_SC_DBG_TX_EMPTY 8 +#define INT_ARM11_PM 9 +#define INT_AVS_REQ_DOWN 10 +#define INT_AVS_REQ_UP 11 +#define INT_SC_ACG 12 +/* SCSS_VICFIQSTS0[13:15] are RESERVED */ +#define INT_L2_SVICCPUIRPTREQ 16 +#define INT_L2_SVICDMANSIRPTREQ 17 +#define INT_L2_SVICDMASIRPTREQ 18 +#define INT_L2_SVICSLVIRPTREQ 19 +#define INT_AD5A_MPROC_APPS_0 20 +#define INT_AD5A_MPROC_APPS_1 21 +#define INT_A9_M2A_0 22 +#define INT_A9_M2A_1 23 +#define INT_A9_M2A_2 24 +#define INT_A9_M2A_3 25 +#define INT_A9_M2A_4 26 +#define INT_A9_M2A_5 27 +#define INT_A9_M2A_6 28 +#define INT_A9_M2A_7 29 +#define INT_A9_M2A_8 30 +#define INT_A9_M2A_9 31 + +#define INT_AXI_EBI1_SC (32 + 0) +#define INT_IMEM_ERR (32 + 1) +#define INT_AXI_EBI0_SC (32 + 2) +#define INT_PBUS_SC_IRQC (32 + 3) +#define INT_PERPH_BUS_BPM (32 + 4) +#define INT_CC_TEMP_SENSE (32 + 5) +#define INT_UXMC_EBI0 (32 + 6) +#define INT_UXMC_EBI1 (32 + 7) +#define INT_EBI2_OP_DONE (32 + 8) +#define INT_EBI2_WR_ER_DONE (32 + 9) +#define INT_TCSR_SPSS_CE (32 + 10) +#define INT_EMDH (32 + 11) +#define INT_PMDH (32 + 12) +#define INT_MDC (32 + 13) +#define INT_MIDI_TO_SUPSS (32 + 14) +#define INT_LPA_2 (32 + 15) +#define INT_GPIO_GROUP1_SECURE (32 + 16) +#define INT_GPIO_GROUP2_SECURE (32 + 17) +#define INT_GPIO_GROUP1 (32 + 18) +#define INT_GPIO_GROUP2 (32 + 19) +#define INT_MPRPH_SOFTRESET (32 + 20) +#define INT_PWB_I2C (32 + 21) +#define INT_PWB_I2C_2 (32 + 22) +#define INT_TSSC_SAMPLE (32 + 23) +#define INT_TSSC_PENUP (32 + 24) +#define INT_TCHSCRN_SSBI (32 + 25) +#define INT_FM_RDS (32 + 26) +#define INT_KEYSENSE (32 + 27) +#define INT_USB_OTG_HS (32 + 28) +#define INT_USB_OTG_HS2 (32 + 29) +#define INT_USB_OTG_HS3 (32 + 30) +#define INT_CSI (32 + 31) + +#define INT_SPI_OUTPUT (64 + 0) +#define INT_SPI_INPUT (64 + 1) +#define INT_SPI_ERROR (64 + 2) +#define INT_UART1 (64 + 3) +#define INT_UART1_RX (64 + 4) +#define INT_UART2 (64 + 5) +#define INT_UART2_RX (64 + 6) +#define INT_UART3 (64 + 7) +#define INT_UART3_RX (64 + 8) +#define INT_UART1DM_IRQ (64 + 9) +#define INT_UART1DM_RX (64 + 10) +#define INT_UART2DM_IRQ (64 + 11) +#define INT_UART2DM_RX (64 + 12) +#define INT_TSIF (64 + 13) +#define INT_ADM_SC1 (64 + 14) +#define INT_ADM_SC2 (64 + 15) +#define INT_MDP (64 + 16) +#define INT_VPE (64 + 17) +#define INT_GRP_2D (64 + 18) +#define INT_GRP_3D (64 + 19) +#define INT_ROTATOR (64 + 20) +#define INT_MFC720 (64 + 21) +#define INT_JPEG (64 + 22) +#define INT_VFE (64 + 23) +#define INT_TV_ENC (64 + 24) +#define INT_PMIC_SSBI (64 + 25) +#define INT_MPM_1 (64 + 26) +#define INT_TCSR_SPSS_SAMPLE (64 + 27) +#define INT_TCSR_SPSS_PENUP (64 + 28) +#define INT_MPM_2 (64 + 29) +#define INT_SDC1_0 (64 + 30) +#define INT_SDC1_1 (64 + 31) + +#define INT_SDC3_0 (96 + 0) +#define INT_SDC3_1 (96 + 1) +#define INT_SDC2_0 (96 + 2) +#define INT_SDC2_1 (96 + 3) +#define INT_SDC4_0 (96 + 4) +#define INT_SDC4_1 (96 + 5) +#define INT_PWB_QUP_IN (96 + 6) +#define INT_PWB_QUP_OUT (96 + 7) +#define INT_PWB_QUP_ERR (96 + 8) +#define INT_SCSS_WDT0_BITE (96 + 9) +/* SCSS_VICFIQSTS3[10:31] are RESERVED */ + +/* Retrofit universal macro names */ +#define INT_ADM_AARM INT_ADM_SC2 +#define INT_USB_HS INT_USB_OTG_HS +#define INT_USB_OTG INT_USB_OTG_HS +#define INT_TCHSCRN1 INT_TSSC_SAMPLE +#define INT_TCHSCRN2 INT_TSSC_PENUP +#define INT_GP_TIMER_EXP INT_GPT0_TIMER_EXP +#define INT_ADSP_A11 INT_AD5A_MPROC_APPS_0 +#define INT_ADSP_A9_A11 INT_AD5A_MPROC_APPS_1 +#define INT_MDDI_EXT INT_EMDH +#define INT_MDDI_PRI INT_PMDH +#define INT_MDDI_CLIENT INT_MDC +#define INT_NAND_WR_ER_DONE INT_EBI2_WR_ER_DONE +#define INT_NAND_OP_DONE INT_EBI2_OP_DONE + +#define NR_MSM_IRQS 128 +#define NR_GPIO_IRQS 182 +#define PMIC8058_IRQ_BASE (NR_MSM_IRQS + NR_GPIO_IRQS) +#define NR_PMIC8058_GPIO_IRQS 40 +#define NR_PMIC8058_MPP_IRQS 12 +#define NR_PMIC8058_MISC_IRQS 8 +#define NR_PMIC8058_IRQS (NR_PMIC8058_GPIO_IRQS +\ + NR_PMIC8058_MPP_IRQS +\ + NR_PMIC8058_MISC_IRQS) +#define NR_BOARD_IRQS NR_PMIC8058_IRQS + +#endif /* __ASM_ARCH_MSM_IRQS_7X30_H */ diff --git a/arch/arm/mach-msm/include/mach/irqs-8x50.h b/arch/arm/mach-msm/include/mach/irqs-8x50.h new file mode 100644 index 000000000000..de3d8fe24e4e --- /dev/null +++ b/arch/arm/mach-msm/include/mach/irqs-8x50.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM_ARCH_MSM_IRQS_8XXX_H +#define __ASM_ARCH_MSM_IRQS_8XXX_H + +/* MSM ACPU Interrupt Numbers */ + +#define INT_A9_M2A_0 0 +#define INT_A9_M2A_1 1 +#define INT_A9_M2A_2 2 +#define INT_A9_M2A_3 3 +#define INT_A9_M2A_4 4 +#define INT_A9_M2A_5 5 +#define INT_A9_M2A_6 6 +#define INT_GP_TIMER_EXP 7 +#define INT_DEBUG_TIMER_EXP 8 +#define INT_SIRC_0 9 +#define INT_SDC3_0 10 +#define INT_SDC3_1 11 +#define INT_SDC4_0 12 +#define INT_SDC4_1 13 +#define INT_AD6_EXT_VFR 14 +#define INT_USB_OTG 15 +#define INT_MDDI_PRI 16 +#define INT_MDDI_EXT 17 +#define INT_MDDI_CLIENT 18 +#define INT_MDP 19 +#define INT_GRAPHICS 20 +#define INT_ADM_AARM 21 +#define INT_ADSP_A11 22 +#define INT_ADSP_A9_A11 23 +#define INT_SDC1_0 24 +#define INT_SDC1_1 25 +#define INT_SDC2_0 26 +#define INT_SDC2_1 27 +#define INT_KEYSENSE 28 +#define INT_TCHSCRN_SSBI 29 +#define INT_TCHSCRN1 30 +#define INT_TCHSCRN2 31 + +#define INT_TCSR_MPRPH_SC1 (32 + 0) +#define INT_USB_FS2 (32 + 1) +#define INT_PWB_I2C (32 + 2) +#define INT_SOFTRESET (32 + 3) +#define INT_NAND_WR_ER_DONE (32 + 4) +#define INT_NAND_OP_DONE (32 + 5) +#define INT_TCSR_MPRPH_SC2 (32 + 6) +#define INT_OP_PEN (32 + 7) +#define INT_AD_HSSD (32 + 8) +#define INT_ARM11_PM (32 + 9) +#define INT_SDMA_NON_SECURE (32 + 10) +#define INT_TSIF_IRQ (32 + 11) +#define INT_UART1DM_IRQ (32 + 12) +#define INT_UART1DM_RX (32 + 13) +#define INT_SDMA_SECURE (32 + 14) +#define INT_SI2S_SLAVE (32 + 15) +#define INT_SC_I2CPU (32 + 16) +#define INT_SC_DBG_RDTRFULL (32 + 17) +#define INT_SC_DBG_WDTRFULL (32 + 18) +#define INT_SCPLL_CTL_DONE (32 + 19) +#define INT_UART2DM_IRQ (32 + 20) +#define INT_UART2DM_RX (32 + 21) +#define INT_VDC_MEC (32 + 22) +#define INT_VDC_DB (32 + 23) +#define INT_VDC_AXI (32 + 24) +#define INT_VFE (32 + 25) +#define INT_USB_HS (32 + 26) +#define INT_AUDIO_OUT0 (32 + 27) +#define INT_AUDIO_OUT1 (32 + 28) +#define INT_CRYPTO (32 + 29) +#define INT_AD6M_IDLE (32 + 30) +#define INT_SIRC_1 (32 + 31) + +#define NR_GPIO_IRQS 165 +#define NR_MSM_IRQS 64 +#define NR_BOARD_IRQS 64 + +#endif diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h index 9dd4cf8a2693..164d355c96ea 100644 --- a/arch/arm/mach-msm/include/mach/irqs.h +++ b/arch/arm/mach-msm/include/mach/irqs.h @@ -1,6 +1,6 @@ -/* arch/arm/mach-msm/include/mach/irqs.h - * +/* * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -17,74 +17,21 @@ #ifndef __ASM_ARCH_MSM_IRQS_H #define __ASM_ARCH_MSM_IRQS_H -/* MSM ARM11 Interrupt Numbers */ -/* See 80-VE113-1 A, pp219-221 */ - -#define INT_A9_M2A_0 0 -#define INT_A9_M2A_1 1 -#define INT_A9_M2A_2 2 -#define INT_A9_M2A_3 3 -#define INT_A9_M2A_4 4 -#define INT_A9_M2A_5 5 -#define INT_A9_M2A_6 6 -#define INT_GP_TIMER_EXP 7 -#define INT_DEBUG_TIMER_EXP 8 -#define INT_UART1 9 -#define INT_UART2 10 -#define INT_UART3 11 -#define INT_UART1_RX 12 -#define INT_UART2_RX 13 -#define INT_UART3_RX 14 -#define INT_USB_OTG 15 -#define INT_MDDI_PRI 16 -#define INT_MDDI_EXT 17 -#define INT_MDDI_CLIENT 18 -#define INT_MDP 19 -#define INT_GRAPHICS 20 -#define INT_ADM_AARM 21 -#define INT_ADSP_A11 22 -#define INT_ADSP_A9_A11 23 -#define INT_SDC1_0 24 -#define INT_SDC1_1 25 -#define INT_SDC2_0 26 -#define INT_SDC2_1 27 -#define INT_KEYSENSE 28 -#define INT_TCHSCRN_SSBI 29 -#define INT_TCHSCRN1 30 -#define INT_TCHSCRN2 31 - -#define INT_GPIO_GROUP1 (32 + 0) -#define INT_GPIO_GROUP2 (32 + 1) -#define INT_PWB_I2C (32 + 2) -#define INT_SOFTRESET (32 + 3) -#define INT_NAND_WR_ER_DONE (32 + 4) -#define INT_NAND_OP_DONE (32 + 5) -#define INT_PBUS_ARM11 (32 + 6) -#define INT_AXI_MPU_SMI (32 + 7) -#define INT_AXI_MPU_EBI1 (32 + 8) -#define INT_AD_HSSD (32 + 9) -#define INT_ARM11_PMU (32 + 10) -#define INT_ARM11_DMA (32 + 11) -#define INT_TSIF_IRQ (32 + 12) -#define INT_UART1DM_IRQ (32 + 13) -#define INT_UART1DM_RX (32 + 14) -#define INT_USB_HS (32 + 15) -#define INT_SDC3_0 (32 + 16) -#define INT_SDC3_1 (32 + 17) -#define INT_SDC4_0 (32 + 18) -#define INT_SDC4_1 (32 + 19) -#define INT_UART2DM_RX (32 + 20) -#define INT_UART2DM_IRQ (32 + 21) - -/* 22-31 are reserved */ - #define MSM_IRQ_BIT(irq) (1 << ((irq) & 31)) -#define NR_MSM_IRQS 64 -#define NR_GPIO_IRQS 122 -#define NR_BOARD_IRQS 64 -#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS) +#if defined(CONFIG_ARCH_MSM7X30) +#include "irqs-7x30.h" +#elif defined(CONFIG_ARCH_QSD8X50) +#include "irqs-8x50.h" +#include "sirc.h" +#elif defined(CONFIG_ARCH_MSM_ARM11) +#include "irqs-7x00.h" +#else +#error "Unknown architecture specification" +#endif +#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS) #define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n)) +#define MSM_INT_TO_REG(base, irq) (base + irq / 32) #endif diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index f4698baec976..50c7847e6002 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -17,7 +17,15 @@ #define __ASM_ARCH_MEMORY_H /* physical offset of RAM */ +#if defined(CONFIG_ARCH_QSD8X50) && defined(CONFIG_MSM_SOC_REV_A) +#define PHYS_OFFSET UL(0x00000000) +#elif defined(CONFIG_ARCH_QSD8X50) +#define PHYS_OFFSET UL(0x20000000) +#elif defined(CONFIG_ARCH_MSM7X30) +#define PHYS_OFFSET UL(0x00200000) +#else #define PHYS_OFFSET UL(0x10000000) +#endif #endif diff --git a/arch/arm/mach-msm/include/mach/msm_fb.h b/arch/arm/mach-msm/include/mach/msm_fb.h new file mode 100644 index 000000000000..1f4fc81b3d8f --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_fb.h @@ -0,0 +1,147 @@ +/* arch/arm/mach-msm/include/mach/msm_fb.h + * + * Internal shared definitions for various MSM framebuffer parts. + * + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MSM_FB_H_ +#define _MSM_FB_H_ + +#include <linux/device.h> + +struct mddi_info; + +struct msm_fb_data { + int xres; /* x resolution in pixels */ + int yres; /* y resolution in pixels */ + int width; /* disply width in mm */ + int height; /* display height in mm */ + unsigned output_format; +}; + +struct msmfb_callback { + void (*func)(struct msmfb_callback *); +}; + +enum { + MSM_MDDI_PMDH_INTERFACE, + MSM_MDDI_EMDH_INTERFACE, + MSM_EBI2_INTERFACE, +}; + +#define MSMFB_CAP_PARTIAL_UPDATES (1 << 0) + +struct msm_panel_data { + /* turns off the fb memory */ + int (*suspend)(struct msm_panel_data *); + /* turns on the fb memory */ + int (*resume)(struct msm_panel_data *); + /* turns off the panel */ + int (*blank)(struct msm_panel_data *); + /* turns on the panel */ + int (*unblank)(struct msm_panel_data *); + void (*wait_vsync)(struct msm_panel_data *); + void (*request_vsync)(struct msm_panel_data *, struct msmfb_callback *); + void (*clear_vsync)(struct msm_panel_data *); + /* from the enum above */ + unsigned interface_type; + /* data to be passed to the fb driver */ + struct msm_fb_data *fb_data; + + /* capabilities supported by the panel */ + uint32_t caps; +}; + +struct msm_mddi_client_data { + void (*suspend)(struct msm_mddi_client_data *); + void (*resume)(struct msm_mddi_client_data *); + void (*activate_link)(struct msm_mddi_client_data *); + void (*remote_write)(struct msm_mddi_client_data *, uint32_t val, + uint32_t reg); + uint32_t (*remote_read)(struct msm_mddi_client_data *, uint32_t reg); + void (*auto_hibernate)(struct msm_mddi_client_data *, int); + /* custom data that needs to be passed from the board file to a + * particular client */ + void *private_client_data; + struct resource *fb_resource; + /* from the list above */ + unsigned interface_type; +}; + +struct msm_mddi_platform_data { + unsigned int clk_rate; + void (*power_client)(struct msm_mddi_client_data *, int on); + + /* fixup the mfr name, product id */ + void (*fixup)(uint16_t *mfr_name, uint16_t *product_id); + + struct resource *fb_resource; /*optional*/ + /* number of clients in the list that follows */ + int num_clients; + /* array of client information of clients */ + struct { + unsigned product_id; /* mfr id in top 16 bits, product id + * in lower 16 bits + */ + char *name; /* the device name will be the platform + * device name registered for the client, + * it should match the name of the associated + * driver + */ + unsigned id; /* id for mddi client device node, will also + * be used as device id of panel devices, if + * the client device will have multiple panels + * space must be left here for them + */ + void *client_data; /* required private client data */ + unsigned int clk_rate; /* optional: if the client requires a + * different mddi clk rate + */ + } client_platform_data[]; +}; + +struct mdp_blit_req; +struct fb_info; +struct mdp_device { + struct device dev; + void (*dma)(struct mdp_device *mpd, uint32_t addr, + uint32_t stride, uint32_t w, uint32_t h, uint32_t x, + uint32_t y, struct msmfb_callback *callback, int interface); + void (*dma_wait)(struct mdp_device *mdp); + int (*blit)(struct mdp_device *mdp, struct fb_info *fb, + struct mdp_blit_req *req); + void (*set_grp_disp)(struct mdp_device *mdp, uint32_t disp_id); +}; + +struct class_interface; +int register_mdp_client(struct class_interface *class_intf); + +/**** private client data structs go below this line ***/ + +struct msm_mddi_bridge_platform_data { + /* from board file */ + int (*init)(struct msm_mddi_bridge_platform_data *, + struct msm_mddi_client_data *); + int (*uninit)(struct msm_mddi_bridge_platform_data *, + struct msm_mddi_client_data *); + /* passed to panel for use by the fb driver */ + int (*blank)(struct msm_mddi_bridge_platform_data *, + struct msm_mddi_client_data *); + int (*unblank)(struct msm_mddi_bridge_platform_data *, + struct msm_mddi_client_data *); + struct msm_fb_data fb_data; +}; + + + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h new file mode 100644 index 000000000000..cfff0e74f128 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h @@ -0,0 +1,139 @@ +/* arch/arm/mach-msm/include/mach/msm_iomap.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * The MSM peripherals are spread all over across 768MB of physical + * space, which makes just having a simple IO_ADDRESS macro to slide + * them into the right virtual location rough. Instead, we will + * provide a master phys->virt mapping for peripherals here. + * + */ + +#ifndef __ASM_ARCH_MSM_IOMAP_7X00_H +#define __ASM_ARCH_MSM_IOMAP_7X00_H + +#include <asm/sizes.h> + +/* Physical base address and size of peripherals. + * Ordered by the virtual base addresses they will be mapped at. + * + * MSM_VIC_BASE must be an value that can be loaded via a "mov" + * instruction, otherwise entry-macro.S will not compile. + * + * If you add or remove entries here, you'll want to edit the + * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your + * changes. + * + */ + +#ifdef __ASSEMBLY__ +#define IOMEM(x) x +#else +#define IOMEM(x) ((void __force __iomem *)(x)) +#endif + +#define MSM_VIC_BASE IOMEM(0xE0000000) +#define MSM_VIC_PHYS 0xC0000000 +#define MSM_VIC_SIZE SZ_4K + +#define MSM_CSR_BASE IOMEM(0xE0001000) +#define MSM_CSR_PHYS 0xC0100000 +#define MSM_CSR_SIZE SZ_4K + +#define MSM_GPT_PHYS MSM_CSR_PHYS +#define MSM_GPT_BASE MSM_CSR_BASE +#define MSM_GPT_SIZE SZ_4K + +#define MSM_DMOV_BASE IOMEM(0xE0002000) +#define MSM_DMOV_PHYS 0xA9700000 +#define MSM_DMOV_SIZE SZ_4K + +#define MSM_GPIO1_BASE IOMEM(0xE0003000) +#define MSM_GPIO1_PHYS 0xA9200000 +#define MSM_GPIO1_SIZE SZ_4K + +#define MSM_GPIO2_BASE IOMEM(0xE0004000) +#define MSM_GPIO2_PHYS 0xA9300000 +#define MSM_GPIO2_SIZE SZ_4K + +#define MSM_CLK_CTL_BASE IOMEM(0xE0005000) +#define MSM_CLK_CTL_PHYS 0xA8600000 +#define MSM_CLK_CTL_SIZE SZ_4K + +#define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) +#define MSM_SHARED_RAM_PHYS 0x01F00000 +#define MSM_SHARED_RAM_SIZE SZ_1M + +#define MSM_UART1_PHYS 0xA9A00000 +#define MSM_UART1_SIZE SZ_4K + +#define MSM_UART2_PHYS 0xA9B00000 +#define MSM_UART2_SIZE SZ_4K + +#define MSM_UART3_PHYS 0xA9C00000 +#define MSM_UART3_SIZE SZ_4K + +#ifdef CONFIG_MSM_DEBUG_UART +#define MSM_DEBUG_UART_BASE 0xE1000000 +#if CONFIG_MSM_DEBUG_UART == 1 +#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS +#elif CONFIG_MSM_DEBUG_UART == 2 +#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS +#elif CONFIG_MSM_DEBUG_UART == 3 +#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS +#endif +#define MSM_DEBUG_UART_SIZE SZ_4K +#endif + +#define MSM_SDC1_PHYS 0xA0400000 +#define MSM_SDC1_SIZE SZ_4K + +#define MSM_SDC2_PHYS 0xA0500000 +#define MSM_SDC2_SIZE SZ_4K + +#define MSM_SDC3_PHYS 0xA0600000 +#define MSM_SDC3_SIZE SZ_4K + +#define MSM_SDC4_PHYS 0xA0700000 +#define MSM_SDC4_SIZE SZ_4K + +#define MSM_I2C_PHYS 0xA9900000 +#define MSM_I2C_SIZE SZ_4K + +#define MSM_HSUSB_PHYS 0xA0800000 +#define MSM_HSUSB_SIZE SZ_4K + +#define MSM_PMDH_PHYS 0xAA600000 +#define MSM_PMDH_SIZE SZ_4K + +#define MSM_EMDH_PHYS 0xAA700000 +#define MSM_EMDH_SIZE SZ_4K + +#define MSM_MDP_PHYS 0xAA200000 +#define MSM_MDP_SIZE 0x000F0000 + +#define MSM_MDC_PHYS 0xAA500000 +#define MSM_MDC_SIZE SZ_1M + +#define MSM_AD5_PHYS 0xAC000000 +#define MSM_AD5_SIZE (SZ_1M*13) + + +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_GCC_BASE IOMEM(0xF8009000) +#define MSM_GCC_PHYS 0xC0182000 +#define MSM_GCC_SIZE SZ_4K +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h new file mode 100644 index 000000000000..8a00c2defbc1 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * The MSM peripherals are spread all over across 768MB of physical + * space, which makes just having a simple IO_ADDRESS macro to slide + * them into the right virtual location rough. Instead, we will + * provide a master phys->virt mapping for peripherals here. + * + */ + +#ifndef __ASM_ARCH_MSM_IOMAP_7X30_H +#define __ASM_ARCH_MSM_IOMAP_7X30_H + +/* Physical base address and size of peripherals. + * Ordered by the virtual base addresses they will be mapped at. + * + * MSM_VIC_BASE must be an value that can be loaded via a "mov" + * instruction, otherwise entry-macro.S will not compile. + * + * If you add or remove entries here, you'll want to edit the + * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your + * changes. + * + */ + +#define MSM_VIC_BASE IOMEM(0xE0000000) +#define MSM_VIC_PHYS 0xC0080000 +#define MSM_VIC_SIZE SZ_4K + +#define MSM_CSR_BASE IOMEM(0xE0001000) +#define MSM_CSR_PHYS 0xC0100000 +#define MSM_CSR_SIZE SZ_4K + +#define MSM_TMR_PHYS MSM_CSR_PHYS +#define MSM_TMR_BASE MSM_CSR_BASE +#define MSM_TMR_SIZE SZ_4K + +#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4) +#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24) + +#define MSM_DMOV_BASE IOMEM(0xE0002000) +#define MSM_DMOV_PHYS 0xAC400000 +#define MSM_DMOV_SIZE SZ_4K + +#define MSM_GPIO1_BASE IOMEM(0xE0003000) +#define MSM_GPIO1_PHYS 0xAC001000 +#define MSM_GPIO1_SIZE SZ_4K + +#define MSM_GPIO2_BASE IOMEM(0xE0004000) +#define MSM_GPIO2_PHYS 0xAC101000 +#define MSM_GPIO2_SIZE SZ_4K + +#define MSM_CLK_CTL_BASE IOMEM(0xE0005000) +#define MSM_CLK_CTL_PHYS 0xAB800000 +#define MSM_CLK_CTL_SIZE SZ_4K + +#define MSM_CLK_CTL_SH2_BASE IOMEM(0xE0006000) +#define MSM_CLK_CTL_SH2_PHYS 0xABA01000 +#define MSM_CLK_CTL_SH2_SIZE SZ_4K + +#define MSM_ACC_BASE IOMEM(0xE0007000) +#define MSM_ACC_PHYS 0xC0101000 +#define MSM_ACC_SIZE SZ_4K + +#define MSM_SAW_BASE IOMEM(0xE0008000) +#define MSM_SAW_PHYS 0xC0102000 +#define MSM_SAW_SIZE SZ_4K + +#define MSM_GCC_BASE IOMEM(0xE0009000) +#define MSM_GCC_PHYS 0xC0182000 +#define MSM_GCC_SIZE SZ_4K + +#define MSM_TCSR_BASE IOMEM(0xE000A000) +#define MSM_TCSR_PHYS 0xAB600000 +#define MSM_TCSR_SIZE SZ_4K + +#define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) +#define MSM_SHARED_RAM_PHYS 0x00100000 +#define MSM_SHARED_RAM_SIZE SZ_1M + +#define MSM_UART1_PHYS 0xACA00000 +#define MSM_UART1_SIZE SZ_4K + +#define MSM_UART2_PHYS 0xACB00000 +#define MSM_UART2_SIZE SZ_4K + +#define MSM_UART3_PHYS 0xACC00000 +#define MSM_UART3_SIZE SZ_4K + +#ifdef CONFIG_MSM_DEBUG_UART +#define MSM_DEBUG_UART_BASE 0xE1000000 +#if CONFIG_MSM_DEBUG_UART == 1 +#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS +#elif CONFIG_MSM_DEBUG_UART == 2 +#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS +#elif CONFIG_MSM_DEBUG_UART == 3 +#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS +#endif +#define MSM_DEBUG_UART_SIZE SZ_4K +#endif + +#define MSM_MDC_BASE IOMEM(0xE0200000) +#define MSM_MDC_PHYS 0xAA500000 +#define MSM_MDC_SIZE SZ_1M + +#define MSM_AD5_BASE IOMEM(0xE0300000) +#define MSM_AD5_PHYS 0xA7000000 +#define MSM_AD5_SIZE (SZ_1M*13) + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h new file mode 100644 index 000000000000..acc819eb76e5 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * The MSM peripherals are spread all over across 768MB of physical + * space, which makes just having a simple IO_ADDRESS macro to slide + * them into the right virtual location rough. Instead, we will + * provide a master phys->virt mapping for peripherals here. + * + */ + +#ifndef __ASM_ARCH_MSM_IOMAP_8X50_H +#define __ASM_ARCH_MSM_IOMAP_8X50_H + +/* Physical base address and size of peripherals. + * Ordered by the virtual base addresses they will be mapped at. + * + * MSM_VIC_BASE must be an value that can be loaded via a "mov" + * instruction, otherwise entry-macro.S will not compile. + * + * If you add or remove entries here, you'll want to edit the + * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your + * changes. + * + */ + +#define MSM_VIC_BASE IOMEM(0xE0000000) +#define MSM_VIC_PHYS 0xAC000000 +#define MSM_VIC_SIZE SZ_4K + +#define MSM_CSR_BASE IOMEM(0xE0001000) +#define MSM_CSR_PHYS 0xAC100000 +#define MSM_CSR_SIZE SZ_4K + +#define MSM_TMR_PHYS MSM_CSR_PHYS +#define MSM_TMR_BASE MSM_CSR_BASE +#define MSM_TMR_SIZE SZ_4K + +#define MSM_GPT_BASE MSM_TMR_BASE +#define MSM_DGT_BASE (MSM_TMR_BASE + 0x10) + +#define MSM_DMOV_BASE IOMEM(0xE0002000) +#define MSM_DMOV_PHYS 0xA9700000 +#define MSM_DMOV_SIZE SZ_4K + +#define MSM_GPIO1_BASE IOMEM(0xE0003000) +#define MSM_GPIO1_PHYS 0xA9000000 +#define MSM_GPIO1_SIZE SZ_4K + +#define MSM_GPIO2_BASE IOMEM(0xE0004000) +#define MSM_GPIO2_PHYS 0xA9100000 +#define MSM_GPIO2_SIZE SZ_4K + +#define MSM_CLK_CTL_BASE IOMEM(0xE0005000) +#define MSM_CLK_CTL_PHYS 0xA8600000 +#define MSM_CLK_CTL_SIZE SZ_4K + +#define MSM_SIRC_BASE IOMEM(0xE1006000) +#define MSM_SIRC_PHYS 0xAC200000 +#define MSM_SIRC_SIZE SZ_4K + +#define MSM_SCPLL_BASE IOMEM(0xE1007000) +#define MSM_SCPLL_PHYS 0xA8800000 +#define MSM_SCPLL_SIZE SZ_4K + +#ifdef CONFIG_MSM_SOC_REV_A +#define MSM_SMI_BASE 0xE0000000 +#else +#define MSM_SMI_BASE 0x00000000 +#endif + +#define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) +#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000) +#define MSM_SHARED_RAM_SIZE SZ_1M + +#define MSM_UART1_PHYS 0xA9A00000 +#define MSM_UART1_SIZE SZ_4K + +#define MSM_UART2_PHYS 0xA9B00000 +#define MSM_UART2_SIZE SZ_4K + +#define MSM_UART3_PHYS 0xA9C00000 +#define MSM_UART3_SIZE SZ_4K + +#ifdef CONFIG_MSM_DEBUG_UART +#define MSM_DEBUG_UART_BASE 0xE1000000 +#if CONFIG_MSM_DEBUG_UART == 1 +#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS +#elif CONFIG_MSM_DEBUG_UART == 2 +#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS +#elif CONFIG_MSM_DEBUG_UART == 3 +#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS +#endif +#define MSM_DEBUG_UART_SIZE SZ_4K +#endif + +#define MSM_MDC_BASE IOMEM(0xE0200000) +#define MSM_MDC_PHYS 0xAA500000 +#define MSM_MDC_SIZE SZ_1M + +#define MSM_AD5_BASE IOMEM(0xE0300000) +#define MSM_AD5_PHYS 0xAC000000 +#define MSM_AD5_SIZE (SZ_1M*13) + + +#define MSM_I2C_SIZE SZ_4K +#define MSM_I2C_PHYS 0xA9900000 + +#define MSM_HSUSB_PHYS 0xA0800000 +#define MSM_HSUSB_SIZE SZ_1K + +#define MSM_NAND_PHYS 0xA0A00000 + + +#define MSM_TSIF_PHYS (0xa0100000) +#define MSM_TSIF_SIZE (0x200) + +#define MSM_TSSC_PHYS 0xAA300000 + +#define MSM_UART1DM_PHYS 0xA0200000 +#define MSM_UART2DM_PHYS 0xA0900000 + + +#define MSM_SDC1_PHYS 0xA0400000 +#define MSM_SDC1_SIZE SZ_4K + +#define MSM_SDC2_PHYS 0xA0500000 +#define MSM_SDC2_SIZE SZ_4K + +#define MSM_SDC3_PHYS 0xA0600000 +#define MSM_SDC3_SIZE SZ_4K + +#define MSM_SDC4_PHYS 0xA0700000 +#define MSM_SDC4_SIZE SZ_4K + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 9dae1a98c77a..e6b1821cc4ea 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -1,6 +1,6 @@ -/* arch/arm/mach-msm/include/mach/msm_iomap.h - * +/* * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -43,91 +43,12 @@ #define IOMEM(x) ((void __force __iomem *)(x)) #endif -#define MSM_VIC_BASE IOMEM(0xE0000000) -#define MSM_VIC_PHYS 0xC0000000 -#define MSM_VIC_SIZE SZ_4K - -#define MSM_CSR_BASE IOMEM(0xE0001000) -#define MSM_CSR_PHYS 0xC0100000 -#define MSM_CSR_SIZE SZ_4K - -#define MSM_GPT_PHYS MSM_CSR_PHYS -#define MSM_GPT_BASE MSM_CSR_BASE -#define MSM_GPT_SIZE SZ_4K - -#define MSM_DMOV_BASE IOMEM(0xE0002000) -#define MSM_DMOV_PHYS 0xA9700000 -#define MSM_DMOV_SIZE SZ_4K - -#define MSM_GPIO1_BASE IOMEM(0xE0003000) -#define MSM_GPIO1_PHYS 0xA9200000 -#define MSM_GPIO1_SIZE SZ_4K - -#define MSM_GPIO2_BASE IOMEM(0xE0004000) -#define MSM_GPIO2_PHYS 0xA9300000 -#define MSM_GPIO2_SIZE SZ_4K - -#define MSM_CLK_CTL_BASE IOMEM(0xE0005000) -#define MSM_CLK_CTL_PHYS 0xA8600000 -#define MSM_CLK_CTL_SIZE SZ_4K - -#define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) -#define MSM_SHARED_RAM_PHYS 0x01F00000 -#define MSM_SHARED_RAM_SIZE SZ_1M - -#define MSM_UART1_PHYS 0xA9A00000 -#define MSM_UART1_SIZE SZ_4K - -#define MSM_UART2_PHYS 0xA9B00000 -#define MSM_UART2_SIZE SZ_4K - -#define MSM_UART3_PHYS 0xA9C00000 -#define MSM_UART3_SIZE SZ_4K - -#ifdef CONFIG_MSM_DEBUG_UART -#define MSM_DEBUG_UART_BASE 0xE1000000 -#if CONFIG_MSM_DEBUG_UART == 1 -#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS -#elif CONFIG_MSM_DEBUG_UART == 2 -#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS -#elif CONFIG_MSM_DEBUG_UART == 3 -#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS -#endif -#define MSM_DEBUG_UART_SIZE SZ_4K +#if defined(CONFIG_ARCH_MSM7X30) +#include "msm_iomap-7x30.h" +#elif defined(CONFIG_ARCH_QSD8X50) +#include "msm_iomap-8x50.h" +#else +#include "msm_iomap-7x00.h" #endif -#define MSM_SDC1_PHYS 0xA0400000 -#define MSM_SDC1_SIZE SZ_4K - -#define MSM_SDC2_PHYS 0xA0500000 -#define MSM_SDC2_SIZE SZ_4K - -#define MSM_SDC3_PHYS 0xA0600000 -#define MSM_SDC3_SIZE SZ_4K - -#define MSM_SDC4_PHYS 0xA0700000 -#define MSM_SDC4_SIZE SZ_4K - -#define MSM_I2C_PHYS 0xA9900000 -#define MSM_I2C_SIZE SZ_4K - -#define MSM_HSUSB_PHYS 0xA0800000 -#define MSM_HSUSB_SIZE SZ_4K - -#define MSM_PMDH_PHYS 0xAA600000 -#define MSM_PMDH_SIZE SZ_4K - -#define MSM_EMDH_PHYS 0xAA700000 -#define MSM_EMDH_SIZE SZ_4K - -#define MSM_MDP_PHYS 0xAA200000 -#define MSM_MDP_SIZE 0x000F0000 - -#define MSM_MDC_PHYS 0xAA500000 -#define MSM_MDC_SIZE SZ_1M - -#define MSM_AD5_PHYS 0xAC000000 -#define MSM_AD5_SIZE (SZ_1M*13) - - #endif diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h new file mode 100644 index 000000000000..029463ec8756 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_smd.h @@ -0,0 +1,109 @@ +/* linux/include/asm-arm/arch-msm/msm_smd.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ASM_ARCH_MSM_SMD_H +#define __ASM_ARCH_MSM_SMD_H + +typedef struct smd_channel smd_channel_t; + +extern int (*msm_check_for_modem_crash)(void); + +/* warning: notify() may be called before open returns */ +int smd_open(const char *name, smd_channel_t **ch, void *priv, + void (*notify)(void *priv, unsigned event)); + +#define SMD_EVENT_DATA 1 +#define SMD_EVENT_OPEN 2 +#define SMD_EVENT_CLOSE 3 + +int smd_close(smd_channel_t *ch); + +/* passing a null pointer for data reads and discards */ +int smd_read(smd_channel_t *ch, void *data, int len); + +/* Write to stream channels may do a partial write and return +** the length actually written. +** Write to packet channels will never do a partial write -- +** it will return the requested length written or an error. +*/ +int smd_write(smd_channel_t *ch, const void *data, int len); +int smd_write_atomic(smd_channel_t *ch, const void *data, int len); + +int smd_write_avail(smd_channel_t *ch); +int smd_read_avail(smd_channel_t *ch); + +/* Returns the total size of the current packet being read. +** Returns 0 if no packets available or a stream channel. +*/ +int smd_cur_packet_size(smd_channel_t *ch); + +/* used for tty unthrottling and the like -- causes the notify() +** callback to be called from the same lock context as is used +** when it is called from channel updates +*/ +void smd_kick(smd_channel_t *ch); + + +#if 0 +/* these are interruptable waits which will block you until the specified +** number of bytes are readable or writable. +*/ +int smd_wait_until_readable(smd_channel_t *ch, int bytes); +int smd_wait_until_writable(smd_channel_t *ch, int bytes); +#endif + +typedef enum { + SMD_PORT_DS = 0, + SMD_PORT_DIAG, + SMD_PORT_RPC_CALL, + SMD_PORT_RPC_REPLY, + SMD_PORT_BT, + SMD_PORT_CONTROL, + SMD_PORT_MEMCPY_SPARE1, + SMD_PORT_DATA1, + SMD_PORT_DATA2, + SMD_PORT_DATA3, + SMD_PORT_DATA4, + SMD_PORT_DATA5, + SMD_PORT_DATA6, + SMD_PORT_DATA7, + SMD_PORT_DATA8, + SMD_PORT_DATA9, + SMD_PORT_DATA10, + SMD_PORT_DATA11, + SMD_PORT_DATA12, + SMD_PORT_DATA13, + SMD_PORT_DATA14, + SMD_PORT_DATA15, + SMD_PORT_DATA16, + SMD_PORT_DATA17, + SMD_PORT_DATA18, + SMD_PORT_DATA19, + SMD_PORT_DATA20, + SMD_PORT_GPS_NMEA, + SMD_PORT_BRIDGE_1, + SMD_PORT_BRIDGE_2, + SMD_PORT_BRIDGE_3, + SMD_PORT_BRIDGE_4, + SMD_PORT_BRIDGE_5, + SMD_PORT_LOOPBACK, + SMD_PORT_CS_APPS_MODEM, + SMD_PORT_CS_APPS_DSP, + SMD_PORT_CS_MODEM_DSP, + SMD_NUM_PORTS, +} smd_port_id_type; + +#endif diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h new file mode 100644 index 000000000000..7281337ee28d --- /dev/null +++ b/arch/arm/mach-msm/include/mach/sirc.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM_ARCH_MSM_SIRC_H +#define __ASM_ARCH_MSM_SIRC_H + +struct sirc_regs_t { + void *int_enable; + void *int_enable_clear; + void *int_enable_set; + void *int_type; + void *int_polarity; + void *int_clear; +}; + +struct sirc_cascade_regs { + void *int_status; + unsigned int cascade_irq; +}; + +void msm_init_sirc(void); +void msm_sirc_enter_sleep(void); +void msm_sirc_exit_sleep(void); + +#if defined(CONFIG_ARCH_MSM_SCORPION) + +#include <mach/msm_iomap.h> + +/* + * Secondary interrupt controller interrupts + */ + +#define FIRST_SIRC_IRQ (NR_MSM_IRQS + NR_GPIO_IRQS) + +#define INT_UART1 (FIRST_SIRC_IRQ + 0) +#define INT_UART2 (FIRST_SIRC_IRQ + 1) +#define INT_UART3 (FIRST_SIRC_IRQ + 2) +#define INT_UART1_RX (FIRST_SIRC_IRQ + 3) +#define INT_UART2_RX (FIRST_SIRC_IRQ + 4) +#define INT_UART3_RX (FIRST_SIRC_IRQ + 5) +#define INT_SPI_INPUT (FIRST_SIRC_IRQ + 6) +#define INT_SPI_OUTPUT (FIRST_SIRC_IRQ + 7) +#define INT_SPI_ERROR (FIRST_SIRC_IRQ + 8) +#define INT_GPIO_GROUP1 (FIRST_SIRC_IRQ + 9) +#define INT_GPIO_GROUP2 (FIRST_SIRC_IRQ + 10) +#define INT_GPIO_GROUP1_SECURE (FIRST_SIRC_IRQ + 11) +#define INT_GPIO_GROUP2_SECURE (FIRST_SIRC_IRQ + 12) +#define INT_AVS_SVIC (FIRST_SIRC_IRQ + 13) +#define INT_AVS_REQ_UP (FIRST_SIRC_IRQ + 14) +#define INT_AVS_REQ_DOWN (FIRST_SIRC_IRQ + 15) +#define INT_PBUS_ERR (FIRST_SIRC_IRQ + 16) +#define INT_AXI_ERR (FIRST_SIRC_IRQ + 17) +#define INT_SMI_ERR (FIRST_SIRC_IRQ + 18) +#define INT_EBI1_ERR (FIRST_SIRC_IRQ + 19) +#define INT_IMEM_ERR (FIRST_SIRC_IRQ + 20) +#define INT_TEMP_SENSOR (FIRST_SIRC_IRQ + 21) +#define INT_TV_ENC (FIRST_SIRC_IRQ + 22) +#define INT_GRP2D (FIRST_SIRC_IRQ + 23) +#define INT_GSBI_QUP (FIRST_SIRC_IRQ + 24) +#define INT_SC_ACG (FIRST_SIRC_IRQ + 25) +#define INT_WDT0 (FIRST_SIRC_IRQ + 26) +#define INT_WDT1 (FIRST_SIRC_IRQ + 27) + +#if defined(CONFIG_MSM_SOC_REV_A) +#define NR_SIRC_IRQS 28 +#define SIRC_MASK 0x0FFFFFFF +#else +#define NR_SIRC_IRQS 23 +#define SIRC_MASK 0x007FFFFF +#endif + +#define LAST_SIRC_IRQ (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1) + +#define SPSS_SIRC_INT_SELECT (MSM_SIRC_BASE + 0x00) +#define SPSS_SIRC_INT_ENABLE (MSM_SIRC_BASE + 0x04) +#define SPSS_SIRC_INT_ENABLE_CLEAR (MSM_SIRC_BASE + 0x08) +#define SPSS_SIRC_INT_ENABLE_SET (MSM_SIRC_BASE + 0x0C) +#define SPSS_SIRC_INT_TYPE (MSM_SIRC_BASE + 0x10) +#define SPSS_SIRC_INT_POLARITY (MSM_SIRC_BASE + 0x14) +#define SPSS_SIRC_SECURITY (MSM_SIRC_BASE + 0x18) +#define SPSS_SIRC_IRQ_STATUS (MSM_SIRC_BASE + 0x1C) +#define SPSS_SIRC_IRQ1_STATUS (MSM_SIRC_BASE + 0x20) +#define SPSS_SIRC_RAW_STATUS (MSM_SIRC_BASE + 0x24) +#define SPSS_SIRC_INT_CLEAR (MSM_SIRC_BASE + 0x28) +#define SPSS_SIRC_SOFT_INT (MSM_SIRC_BASE + 0x2C) + +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h index 574ccc493daf..d2e83f42ba16 100644 --- a/arch/arm/mach-msm/include/mach/system.h +++ b/arch/arm/mach-msm/include/mach/system.h @@ -21,3 +21,8 @@ static inline void arch_reset(char mode, const char *cmd) { for (;;) ; /* depends on IPC w/ other core */ } + +/* low level hardware reset hook -- for example, hitting the + * PSHOLD line on the PMIC to hard reset the system + */ +extern void (*msm_hw_reset_hook)(void); diff --git a/arch/arm/mach-msm/include/mach/vreg.h b/arch/arm/mach-msm/include/mach/vreg.h index 9f9e25cb718e..6626e7864e28 100644 --- a/arch/arm/mach-msm/include/mach/vreg.h +++ b/arch/arm/mach-msm/include/mach/vreg.h @@ -23,7 +23,7 @@ struct vreg *vreg_get(struct device *dev, const char *id); void vreg_put(struct vreg *vreg); int vreg_enable(struct vreg *vreg); -void vreg_disable(struct vreg *vreg); +int vreg_disable(struct vreg *vreg); int vreg_set_level(struct vreg *vreg, unsigned mv); #endif diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 05f96b780aa6..1c05060b5f3b 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -1,8 +1,9 @@ /* arch/arm/mach-msm/io.c * - * MSM7K io support + * MSM7K, QSD io support * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -34,6 +35,8 @@ .type = MT_DEVICE_NONSHARED, \ } +#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X27) \ + || defined(CONFIG_ARCH_MSM7X25) static struct map_desc msm_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -45,9 +48,12 @@ static struct map_desc msm_io_desc[] __initdata = { #ifdef CONFIG_MSM_DEBUG_UART MSM_DEVICE(DEBUG_UART), #endif +#ifdef CONFIG_ARCH_MSM7X30 + MSM_DEVICE(GCC), +#endif { .virtual = (unsigned long) MSM_SHARED_RAM_BASE, - .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS), + .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS), .length = MSM_SHARED_RAM_SIZE, .type = MT_DEVICE, }, @@ -60,9 +66,72 @@ void __init msm_map_common_io(void) * pages are peripheral interface or not. */ asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0)); - iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc)); } +#endif + +#ifdef CONFIG_ARCH_QSD8X50 +static struct map_desc qsd8x50_io_desc[] __initdata = { + MSM_DEVICE(VIC), + MSM_DEVICE(CSR), + MSM_DEVICE(TMR), + MSM_DEVICE(DMOV), + MSM_DEVICE(GPIO1), + MSM_DEVICE(GPIO2), + MSM_DEVICE(CLK_CTL), + MSM_DEVICE(SIRC), + MSM_DEVICE(SCPLL), + MSM_DEVICE(AD5), + MSM_DEVICE(MDC), +#ifdef CONFIG_MSM_DEBUG_UART + MSM_DEVICE(DEBUG_UART), +#endif + { + .virtual = (unsigned long) MSM_SHARED_RAM_BASE, + .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS), + .length = MSM_SHARED_RAM_SIZE, + .type = MT_DEVICE, + }, +}; + +void __init msm_map_qsd8x50_io(void) +{ + iotable_init(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc)); +} +#endif /* CONFIG_ARCH_QSD8X50 */ + +#ifdef CONFIG_ARCH_MSM7X30 +static struct map_desc msm7x30_io_desc[] __initdata = { + MSM_DEVICE(VIC), + MSM_DEVICE(CSR), + MSM_DEVICE(TMR), + MSM_DEVICE(DMOV), + MSM_DEVICE(GPIO1), + MSM_DEVICE(GPIO2), + MSM_DEVICE(CLK_CTL), + MSM_DEVICE(CLK_CTL_SH2), + MSM_DEVICE(AD5), + MSM_DEVICE(MDC), + MSM_DEVICE(ACC), + MSM_DEVICE(SAW), + MSM_DEVICE(GCC), + MSM_DEVICE(TCSR), +#ifdef CONFIG_MSM_DEBUG_UART + MSM_DEVICE(DEBUG_UART), +#endif + { + .virtual = (unsigned long) MSM_SHARED_RAM_BASE, + .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS), + .length = MSM_SHARED_RAM_SIZE, + .type = MT_DEVICE, + }, +}; + +void __init msm_map_msm7x30_io(void) +{ + iotable_init(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc)); +} +#endif /* CONFIG_ARCH_MSM7X30 */ void __iomem * __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) diff --git a/arch/arm/mach-msm/irq-vic.c b/arch/arm/mach-msm/irq-vic.c new file mode 100644 index 000000000000..99f2c3473033 --- /dev/null +++ b/arch/arm/mach-msm/irq-vic.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/timer.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> + +#include <mach/hardware.h> + +#include <mach/msm_iomap.h> + +#include "smd_private.h" + +enum { + IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0, + IRQ_DEBUG_SLEEP_INT = 1U << 1, + IRQ_DEBUG_SLEEP_ABORT = 1U << 2, + IRQ_DEBUG_SLEEP = 1U << 3, + IRQ_DEBUG_SLEEP_REQUEST = 1U << 4, +}; +static int msm_irq_debug_mask; +module_param_named(debug_mask, msm_irq_debug_mask, int, + S_IRUGO | S_IWUSR | S_IWGRP); + +#define VIC_REG(off) (MSM_VIC_BASE + (off)) +#define VIC_INT_TO_REG_ADDR(base, irq) (base + (irq / 32) * 4) +#define VIC_INT_TO_REG_INDEX(irq) ((irq >> 5) & 3) + +#define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */ +#define VIC_INT_SELECT1 VIC_REG(0x0004) /* 1: FIQ, 0: IRQ */ +#define VIC_INT_SELECT2 VIC_REG(0x0008) /* 1: FIQ, 0: IRQ */ +#define VIC_INT_SELECT3 VIC_REG(0x000C) /* 1: FIQ, 0: IRQ */ +#define VIC_INT_EN0 VIC_REG(0x0010) +#define VIC_INT_EN1 VIC_REG(0x0014) +#define VIC_INT_EN2 VIC_REG(0x0018) +#define VIC_INT_EN3 VIC_REG(0x001C) +#define VIC_INT_ENCLEAR0 VIC_REG(0x0020) +#define VIC_INT_ENCLEAR1 VIC_REG(0x0024) +#define VIC_INT_ENCLEAR2 VIC_REG(0x0028) +#define VIC_INT_ENCLEAR3 VIC_REG(0x002C) +#define VIC_INT_ENSET0 VIC_REG(0x0030) +#define VIC_INT_ENSET1 VIC_REG(0x0034) +#define VIC_INT_ENSET2 VIC_REG(0x0038) +#define VIC_INT_ENSET3 VIC_REG(0x003C) +#define VIC_INT_TYPE0 VIC_REG(0x0040) /* 1: EDGE, 0: LEVEL */ +#define VIC_INT_TYPE1 VIC_REG(0x0044) /* 1: EDGE, 0: LEVEL */ +#define VIC_INT_TYPE2 VIC_REG(0x0048) /* 1: EDGE, 0: LEVEL */ +#define VIC_INT_TYPE3 VIC_REG(0x004C) /* 1: EDGE, 0: LEVEL */ +#define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */ +#define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */ +#define VIC_INT_POLARITY2 VIC_REG(0x0058) /* 1: NEG, 0: POS */ +#define VIC_INT_POLARITY3 VIC_REG(0x005C) /* 1: NEG, 0: POS */ +#define VIC_NO_PEND_VAL VIC_REG(0x0060) + +#if defined(CONFIG_ARCH_MSM_SCORPION) +#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064) +#define VIC_INT_MASTEREN VIC_REG(0x0068) /* 1: IRQ, 2: FIQ */ +#define VIC_CONFIG VIC_REG(0x006C) /* 1: USE SC VIC */ +#else +#define VIC_INT_MASTEREN VIC_REG(0x0064) /* 1: IRQ, 2: FIQ */ +#define VIC_PROTECTION VIC_REG(0x006C) /* 1: ENABLE */ +#define VIC_CONFIG VIC_REG(0x0068) /* 1: USE ARM1136 VIC */ +#endif + +#define VIC_IRQ_STATUS0 VIC_REG(0x0080) +#define VIC_IRQ_STATUS1 VIC_REG(0x0084) +#define VIC_IRQ_STATUS2 VIC_REG(0x0088) +#define VIC_IRQ_STATUS3 VIC_REG(0x008C) +#define VIC_FIQ_STATUS0 VIC_REG(0x0090) +#define VIC_FIQ_STATUS1 VIC_REG(0x0094) +#define VIC_FIQ_STATUS2 VIC_REG(0x0098) +#define VIC_FIQ_STATUS3 VIC_REG(0x009C) +#define VIC_RAW_STATUS0 VIC_REG(0x00A0) +#define VIC_RAW_STATUS1 VIC_REG(0x00A4) +#define VIC_RAW_STATUS2 VIC_REG(0x00A8) +#define VIC_RAW_STATUS3 VIC_REG(0x00AC) +#define VIC_INT_CLEAR0 VIC_REG(0x00B0) +#define VIC_INT_CLEAR1 VIC_REG(0x00B4) +#define VIC_INT_CLEAR2 VIC_REG(0x00B8) +#define VIC_INT_CLEAR3 VIC_REG(0x00BC) +#define VIC_SOFTINT0 VIC_REG(0x00C0) +#define VIC_SOFTINT1 VIC_REG(0x00C4) +#define VIC_SOFTINT2 VIC_REG(0x00C8) +#define VIC_SOFTINT3 VIC_REG(0x00CC) +#define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */ +#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */ +#define VIC_IRQ_VEC_WR VIC_REG(0x00D8) + +#if defined(CONFIG_ARCH_MSM_SCORPION) +#define VIC_FIQ_VEC_RD VIC_REG(0x00DC) +#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0) +#define VIC_FIQ_VEC_WR VIC_REG(0x00E4) +#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E8) +#define VIC_IRQ_IN_STACK VIC_REG(0x00EC) +#define VIC_FIQ_IN_SERVICE VIC_REG(0x00F0) +#define VIC_FIQ_IN_STACK VIC_REG(0x00F4) +#define VIC_TEST_BUS_SEL VIC_REG(0x00F8) +#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC) +#else +#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E0) +#define VIC_IRQ_IN_STACK VIC_REG(0x00E4) +#define VIC_TEST_BUS_SEL VIC_REG(0x00E8) +#endif + +#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4)) +#define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4)) + +#if defined(CONFIG_ARCH_MSM7X30) +#define VIC_NUM_REGS 4 +#else +#define VIC_NUM_REGS 2 +#endif + +#if VIC_NUM_REGS == 2 +#define DPRINT_REGS(base_reg, format, ...) \ + printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__, \ + readl(base_reg ## 0), readl(base_reg ## 1)) +#define DPRINT_ARRAY(array, format, ...) \ + printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__, \ + array[0], array[1]) +#elif VIC_NUM_REGS == 4 +#define DPRINT_REGS(base_reg, format, ...) \ + printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__, \ + readl(base_reg ## 0), readl(base_reg ## 1), \ + readl(base_reg ## 2), readl(base_reg ## 3)) +#define DPRINT_ARRAY(array, format, ...) \ + printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__, \ + array[0], array[1], \ + array[2], array[3]) +#else +#error "VIC_NUM_REGS set to illegal value" +#endif + +static uint32_t msm_irq_smsm_wake_enable[2]; +static struct { + uint32_t int_en[2]; + uint32_t int_type; + uint32_t int_polarity; + uint32_t int_select; +} msm_irq_shadow_reg[VIC_NUM_REGS]; +static uint32_t msm_irq_idle_disable[VIC_NUM_REGS]; + +#define SMSM_FAKE_IRQ (0xff) +static uint8_t msm_irq_to_smsm[NR_IRQS] = { + [INT_MDDI_EXT] = 1, + [INT_MDDI_PRI] = 2, + [INT_MDDI_CLIENT] = 3, + [INT_USB_OTG] = 4, + + [INT_PWB_I2C] = 5, + [INT_SDC1_0] = 6, + [INT_SDC1_1] = 7, + [INT_SDC2_0] = 8, + + [INT_SDC2_1] = 9, + [INT_ADSP_A9_A11] = 10, + [INT_UART1] = 11, + [INT_UART2] = 12, + + [INT_UART3] = 13, + [INT_UART1_RX] = 14, + [INT_UART2_RX] = 15, + [INT_UART3_RX] = 16, + + [INT_UART1DM_IRQ] = 17, + [INT_UART1DM_RX] = 18, + [INT_KEYSENSE] = 19, +#if !defined(CONFIG_ARCH_MSM7X30) + [INT_AD_HSSD] = 20, +#endif + + [INT_NAND_WR_ER_DONE] = 21, + [INT_NAND_OP_DONE] = 22, + [INT_TCHSCRN1] = 23, + [INT_TCHSCRN2] = 24, + + [INT_TCHSCRN_SSBI] = 25, + [INT_USB_HS] = 26, + [INT_UART2DM_RX] = 27, + [INT_UART2DM_IRQ] = 28, + + [INT_SDC4_1] = 29, + [INT_SDC4_0] = 30, + [INT_SDC3_1] = 31, + [INT_SDC3_0] = 32, + + /* fake wakeup interrupts */ + [INT_GPIO_GROUP1] = SMSM_FAKE_IRQ, + [INT_GPIO_GROUP2] = SMSM_FAKE_IRQ, + [INT_A9_M2A_0] = SMSM_FAKE_IRQ, + [INT_A9_M2A_1] = SMSM_FAKE_IRQ, + [INT_A9_M2A_5] = SMSM_FAKE_IRQ, + [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ, + [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ, + [INT_ADSP_A11] = SMSM_FAKE_IRQ, +#ifdef CONFIG_ARCH_QSD8X50 + [INT_SIRC_0] = SMSM_FAKE_IRQ, + [INT_SIRC_1] = SMSM_FAKE_IRQ, +#endif +}; + +static inline void msm_irq_write_all_regs(void __iomem *base, unsigned int val) +{ + int i; + + for (i = 0; i < VIC_NUM_REGS; i++) + writel(val, base + (i * 4)); +} + +static void msm_irq_ack(unsigned int irq) +{ + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, irq); + irq = 1 << (irq & 31); + writel(irq, reg); +} + +static void msm_irq_mask(unsigned int irq) +{ + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); + uint32_t mask = 1UL << (irq & 31); + int smsm_irq = msm_irq_to_smsm[irq]; + + msm_irq_shadow_reg[index].int_en[0] &= ~mask; + writel(mask, reg); + if (smsm_irq == 0) + msm_irq_idle_disable[index] &= ~mask; + else { + mask = 1UL << (smsm_irq - 1); + msm_irq_smsm_wake_enable[0] &= ~mask; + } +} + +static void msm_irq_unmask(unsigned int irq) +{ + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); + uint32_t mask = 1UL << (irq & 31); + int smsm_irq = msm_irq_to_smsm[irq]; + + msm_irq_shadow_reg[index].int_en[0] |= mask; + writel(mask, reg); + + if (smsm_irq == 0) + msm_irq_idle_disable[index] |= mask; + else { + mask = 1UL << (smsm_irq - 1); + msm_irq_smsm_wake_enable[0] |= mask; + } +} + +static int msm_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned index = VIC_INT_TO_REG_INDEX(irq); + uint32_t mask = 1UL << (irq & 31); + int smsm_irq = msm_irq_to_smsm[irq]; + + if (smsm_irq == 0) { + printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq); + return -EINVAL; + } + if (on) + msm_irq_shadow_reg[index].int_en[1] |= mask; + else + msm_irq_shadow_reg[index].int_en[1] &= ~mask; + + if (smsm_irq == SMSM_FAKE_IRQ) + return 0; + + mask = 1UL << (smsm_irq - 1); + if (on) + msm_irq_smsm_wake_enable[1] |= mask; + else + msm_irq_smsm_wake_enable[1] &= ~mask; + return 0; +} + +static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, irq); + void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); + int b = 1 << (irq & 31); + uint32_t polarity; + uint32_t type; + + polarity = msm_irq_shadow_reg[index].int_polarity; + if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) + polarity |= b; + if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) + polarity &= ~b; + writel(polarity, preg); + msm_irq_shadow_reg[index].int_polarity = polarity; + + type = msm_irq_shadow_reg[index].int_type; + if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + type |= b; + irq_desc[irq].handle_irq = handle_edge_irq; + } + if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { + type &= ~b; + irq_desc[irq].handle_irq = handle_level_irq; + } + writel(type, treg); + msm_irq_shadow_reg[index].int_type = type; + return 0; +} + +static struct irq_chip msm_irq_chip = { + .name = "msm", + .disable = msm_irq_mask, + .ack = msm_irq_ack, + .mask = msm_irq_mask, + .unmask = msm_irq_unmask, + .set_wake = msm_irq_set_wake, + .set_type = msm_irq_set_type, +}; + +void __init msm_init_irq(void) +{ + unsigned n; + + /* select level interrupts */ + msm_irq_write_all_regs(VIC_INT_TYPE0, 0); + + /* select highlevel interrupts */ + msm_irq_write_all_regs(VIC_INT_POLARITY0, 0); + + /* select IRQ for all INTs */ + msm_irq_write_all_regs(VIC_INT_SELECT0, 0); + + /* disable all INTs */ + msm_irq_write_all_regs(VIC_INT_EN0, 0); + + /* don't use vic */ + writel(0, VIC_CONFIG); + + /* enable interrupt controller */ + writel(3, VIC_INT_MASTEREN); + + for (n = 0; n < NR_MSM_IRQS; n++) { + set_irq_chip(n, &msm_irq_chip); + set_irq_handler(n, handle_level_irq); + set_irq_flags(n, IRQF_VALID); + } +} diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 69ca0dd79bdf..6c8d5f8caef3 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -101,11 +101,11 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { writel(readl(treg) | b, treg); - set_irq_handler(irq, handle_edge_irq); + irq_desc[irq].handle_irq = handle_edge_irq; } if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { writel(readl(treg) & (~b), treg); - set_irq_handler(irq, handle_level_irq); + irq_desc[irq].handle_irq = handle_level_irq; } return 0; } diff --git a/arch/arm/mach-msm/last_radio_log.c b/arch/arm/mach-msm/last_radio_log.c new file mode 100644 index 000000000000..b64ba5a98686 --- /dev/null +++ b/arch/arm/mach-msm/last_radio_log.c @@ -0,0 +1,82 @@ +/* arch/arm/mach-msm/last_radio_log.c + * + * Extract the log from a modem crash though SMEM + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/uaccess.h> + +#include "smd_private.h" + +static void *radio_log_base; +static size_t radio_log_size; + +extern void *smem_item(unsigned id, unsigned *size); + +static ssize_t last_radio_log_read(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + loff_t pos = *offset; + ssize_t count; + + if (pos >= radio_log_size) + return 0; + + count = min(len, (size_t)(radio_log_size - pos)); + if (copy_to_user(buf, radio_log_base + pos, count)) { + pr_err("%s: copy to user failed\n", __func__); + return -EFAULT; + } + + *offset += count; + return count; +} + +static struct file_operations last_radio_log_fops = { + .read = last_radio_log_read +}; + +void msm_init_last_radio_log(struct module *owner) +{ + struct proc_dir_entry *entry; + + if (last_radio_log_fops.owner) { + pr_err("%s: already claimed\n", __func__); + return; + } + + radio_log_base = smem_item(SMEM_CLKREGIM_BSP, &radio_log_size); + if (!radio_log_base) { + pr_err("%s: could not retrieve SMEM_CLKREGIM_BSP\n", __func__); + return; + } + + entry = create_proc_entry("last_radio_log", S_IFREG | S_IRUGO, NULL); + if (!entry) { + pr_err("%s: could not create proc entry for radio log\n", + __func__); + return; + } + + pr_err("%s: last radio log is %d bytes long\n", __func__, + radio_log_size); + last_radio_log_fops.owner = owner; + entry->proc_fops = &last_radio_log_fops; + entry->size = radio_log_size; +} +EXPORT_SYMBOL(msm_init_last_radio_log); diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c index 915ee704ed3c..67e701c7f183 100644 --- a/arch/arm/mach-msm/proc_comm.c +++ b/arch/arm/mach-msm/proc_comm.c @@ -23,11 +23,18 @@ #include "proc_comm.h" -#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) +static inline void msm_a2m_int(uint32_t irq) +{ +#if defined(CONFIG_ARCH_MSM7X30) + writel(1 << irq, MSM_GCC_BASE + 0x8); +#else + writel(1, MSM_CSR_BASE + 0x400 + (irq * 4)); +#endif +} static inline void notify_other_proc_comm(void) { - writel(1, MSM_A2M_INT(6)); + msm_a2m_int(6); } #define APP_COMMAND 0x00 @@ -107,4 +114,17 @@ int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2) return ret; } - +/* + * We need to wait for the ARM9 to at least partially boot + * up before we can continue. Since the ARM9 does resource + * allocation, if we dont' wait we could end up crashing or in + * and unknown state. This function should be called early to + * wait on the ARM9. + */ +void __init proc_comm_boot_wait(void) +{ + void __iomem *base = MSM_SHARED_RAM_BASE; + + proc_comm_wait_for(base + MDM_STATUS, PCOM_READY); + +} diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index 834760f25692..12da4cacd4a8 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -16,6 +16,8 @@ #ifndef _ARCH_ARM_MACH_MSM_PROC_COMM_H_ #define _ARCH_ARM_MACH_MSM_PROC_COMM_H_ +#include <linux/init.h> + enum { PCOM_CMD_IDLE = 0x0, PCOM_CMD_DONE, @@ -62,19 +64,104 @@ enum { PCOM_RESET_CHIP_IMM, PCOM_PM_VID_EN, PCOM_VREG_PULLDOWN, + PCOM_GET_MODEM_VERSION, + PCOM_CLK_REGIME_SEC_RESET, + PCOM_CLK_REGIME_SEC_RESET_ASSERT, + PCOM_CLK_REGIME_SEC_RESET_DEASSERT, + PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP, + PCOM_CLK_REGIME_SEC_ENABLE, + PCOM_CLK_REGIME_SEC_DISABLE, + PCOM_CLK_REGIME_SEC_IS_ON, + PCOM_CLK_REGIME_SEC_SEL_CLK_INV, + PCOM_CLK_REGIME_SEC_SEL_CLK_SRC, + PCOM_CLK_REGIME_SEC_SEL_CLK_DIV, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE, + PCOM_CLK_REGIME_SEC_SEL_SPEED, + PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP, + PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP, + PCOM_CLK_REGIME_SEC_USB_XTAL_ON, + PCOM_CLK_REGIME_SEC_USB_XTAL_OFF, + PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE, + PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK, + PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ, + PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ, + PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ, + PCOM_CLK_REGIME_SEC_SEL_VFE_SRC, + PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK, + PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK, + PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VFE_RAIL_ON, + PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF, + PCOM_CLK_REGIME_SEC_GRP_RAIL_ON, + PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VDC_RAIL_ON, + PCOM_CLK_REGIME_SEC_LCD_CTRL, + PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP, + PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER, + PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP, + PCOM_GPIO_CONFIG, + PCOM_GPIO_CONFIGURE_GROUP, + PCOM_GPIO_TLMM_SET_PORT, + PCOM_GPIO_TLMM_CONFIG_EX, + PCOM_SET_FTM_BOOT_COUNT, + PCOM_RESERVED0, + PCOM_RESERVED1, + PCOM_CUSTOMER_CMD1, + PCOM_CUSTOMER_CMD2, + PCOM_CUSTOMER_CMD3, + PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_SEC_RAIL_DISABLE, + PCOM_CLK_REGIME_SEC_RAIL_ENABLE, + PCOM_CLK_REGIME_SEC_RAIL_CONTROL, + PCOM_SET_SW_WATCHDOG_STATE, + PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, + PCOM_PM_MPP_CONFIG_I_SINK, + PCOM_RESERVED_101, + PCOM_MSM_HSUSB_PHY_RESET, + PCOM_GET_BATT_MV_LEVEL, + PCOM_CHG_USB_IS_PC_CONNECTED, + PCOM_CHG_USB_IS_CHARGER_CONNECTED, + PCOM_CHG_USB_IS_DISCONNECTED, + PCOM_CHG_USB_IS_AVAILABLE, + PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ, + PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY, + PCOM_CLKCTL_RPC_RESET_ASSERT, + PCOM_CLKCTL_RPC_RESET_DEASSERT, + PCOM_CLKCTL_RPC_RAIL_ON, + PCOM_CLKCTL_RPC_RAIL_OFF, + PCOM_CLKCTL_RPC_RAIL_ENABLE, + PCOM_CLKCTL_RPC_RAIL_DISABLE, + PCOM_CLKCTL_RPC_RAIL_CONTROL, + PCOM_CLKCTL_RPC_MIN_MSMC1, PCOM_NUM_CMDS, }; enum { - PCOM_INVALID_STATUS = 0x0, - PCOM_READY, - PCOM_CMD_RUNNING, - PCOM_CMD_SUCCESS, - PCOM_CMD_FAIL, + PCOM_INVALID_STATUS = 0x0, + PCOM_READY, + PCOM_CMD_RUNNING, + PCOM_CMD_SUCCESS, + PCOM_CMD_FAIL, + PCOM_CMD_FAIL_FALSE_RETURNED, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT, + PCOM_CMD_FAIL_CMD_UNREGISTERED, + PCOM_CMD_FAIL_CMD_LOCKED, + PCOM_CMD_FAIL_SERVER_NOT_YET_READY, + PCOM_CMD_FAIL_BAD_DESTINATION, + PCOM_CMD_FAIL_SERVER_RESET, + PCOM_CMD_FAIL_SMSM_NOT_INIT, + PCOM_CMD_FAIL_PROC_COMM_BUSY, + PCOM_CMD_FAIL_PROC_COMM_NOT_INIT, + }; /* List of VREGs that support the Pull Down Resistor setting. */ -enum { +enum vreg_pdown_id { PM_VREG_PDOWN_MSMA_ID, PM_VREG_PDOWN_MSMP_ID, PM_VREG_PDOWN_MSME1_ID, /* Not supported in Panoramix */ @@ -131,6 +218,11 @@ enum { PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID }; +enum { + PCOM_CLKRGM_APPS_RESET_USB_PHY = 34, + PCOM_CLKRGM_APPS_RESET_USBH = 37, +}; + /* gpio info for PCOM_RPC_GPIO_TLMM_CONFIG_EX */ #define GPIO_ENABLE 0 @@ -161,5 +253,6 @@ enum { (((drvstr) & 0xF) << 17)) int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2); +void __init proc_comm_boot_wait(void); #endif diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c new file mode 100644 index 000000000000..b0794524ba6e --- /dev/null +++ b/arch/arm/mach-msm/sirc.c @@ -0,0 +1,177 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <asm/irq.h> + +static unsigned int int_enable; +static unsigned int wake_enable; + +static struct sirc_regs_t sirc_regs = { + .int_enable = SPSS_SIRC_INT_ENABLE, + .int_enable_clear = SPSS_SIRC_INT_ENABLE_CLEAR, + .int_enable_set = SPSS_SIRC_INT_ENABLE_SET, + .int_type = SPSS_SIRC_INT_TYPE, + .int_polarity = SPSS_SIRC_INT_POLARITY, + .int_clear = SPSS_SIRC_INT_CLEAR, +}; + +static struct sirc_cascade_regs sirc_reg_table[] = { + { + .int_status = SPSS_SIRC_IRQ_STATUS, + .cascade_irq = INT_SIRC_0, + } +}; + +static unsigned int save_type; +static unsigned int save_polarity; + +/* Mask off the given interrupt. Keep the int_enable mask in sync with + the enable reg, so it can be restored after power collapse. */ +static void sirc_irq_mask(unsigned int irq) +{ + unsigned int mask; + + + mask = 1 << (irq - FIRST_SIRC_IRQ); + writel(mask, sirc_regs.int_enable_clear); + int_enable &= ~mask; + return; +} + +/* Unmask the given interrupt. Keep the int_enable mask in sync with + the enable reg, so it can be restored after power collapse. */ +static void sirc_irq_unmask(unsigned int irq) +{ + unsigned int mask; + + mask = 1 << (irq - FIRST_SIRC_IRQ); + writel(mask, sirc_regs.int_enable_set); + int_enable |= mask; + return; +} + +static void sirc_irq_ack(unsigned int irq) +{ + unsigned int mask; + + mask = 1 << (irq - FIRST_SIRC_IRQ); + writel(mask, sirc_regs.int_clear); + return; +} + +static int sirc_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned int mask; + + /* Used to set the interrupt enable mask during power collapse. */ + mask = 1 << (irq - FIRST_SIRC_IRQ); + if (on) + wake_enable |= mask; + else + wake_enable &= ~mask; + + return 0; +} + +static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + unsigned int mask; + unsigned int val; + + mask = 1 << (irq - FIRST_SIRC_IRQ); + val = readl(sirc_regs.int_polarity); + + if (flow_type & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING)) + val |= mask; + else + val &= ~mask; + + writel(val, sirc_regs.int_polarity); + + val = readl(sirc_regs.int_type); + if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + val |= mask; + irq_desc[irq].handle_irq = handle_edge_irq; + } else { + val &= ~mask; + irq_desc[irq].handle_irq = handle_level_irq; + } + + writel(val, sirc_regs.int_type); + + return 0; +} + +/* Finds the pending interrupt on the passed cascade irq and redrives it */ +static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + unsigned int reg = 0; + unsigned int sirq; + unsigned int status; + + while ((reg < ARRAY_SIZE(sirc_reg_table)) && + (sirc_reg_table[reg].cascade_irq != irq)) + reg++; + + status = readl(sirc_reg_table[reg].int_status); + status &= SIRC_MASK; + if (status == 0) + return; + + for (sirq = 0; + (sirq < NR_SIRC_IRQS) && ((status & (1U << sirq)) == 0); + sirq++) + ; + generic_handle_irq(sirq+FIRST_SIRC_IRQ); + + desc->chip->ack(irq); +} + +static struct irq_chip sirc_irq_chip = { + .name = "sirc", + .ack = sirc_irq_ack, + .mask = sirc_irq_mask, + .unmask = sirc_irq_unmask, + .set_wake = sirc_irq_set_wake, + .set_type = sirc_irq_set_type, +}; + +void __init msm_init_sirc(void) +{ + int i; + + int_enable = 0; + wake_enable = 0; + + for (i = FIRST_SIRC_IRQ; i < LAST_SIRC_IRQ; i++) { + set_irq_chip(i, &sirc_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + for (i = 0; i < ARRAY_SIZE(sirc_reg_table); i++) { + set_irq_chained_handler(sirc_reg_table[i].cascade_irq, + sirc_irq_handler); + set_irq_wake(sirc_reg_table[i].cascade_irq, 1); + } + return; +} + diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c new file mode 100644 index 000000000000..cf11d414b425 --- /dev/null +++ b/arch/arm/mach-msm/smd.c @@ -0,0 +1,1046 @@ +/* arch/arm/mach-msm/smd.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/wait.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/debugfs.h> +#include <linux/delay.h> + +#include <mach/msm_smd.h> +#include <mach/system.h> + +#include "smd_private.h" +#include "proc_comm.h" + +#if defined(CONFIG_ARCH_QSD8X50) +#define CONFIG_QDSP6 1 +#endif + +void (*msm_hw_reset_hook)(void); + +#define MODULE_NAME "msm_smd" + +enum { + MSM_SMD_DEBUG = 1U << 0, + MSM_SMSM_DEBUG = 1U << 0, +}; + +static int msm_smd_debug_mask; + +struct shared_info { + int ready; + unsigned state; +}; + +static unsigned dummy_state[SMSM_STATE_COUNT]; + +static struct shared_info smd_info = { + .state = (unsigned) &dummy_state, +}; + +module_param_named(debug_mask, msm_smd_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +static unsigned last_heap_free = 0xffffffff; + +static inline void notify_other_smsm(void) +{ + msm_a2m_int(5); +#ifdef CONFIG_QDSP6 + msm_a2m_int(8); +#endif +} + +static inline void notify_modem_smd(void) +{ + msm_a2m_int(0); +} + +static inline void notify_dsp_smd(void) +{ + msm_a2m_int(8); +} + +static void smd_diag(void) +{ + char *x; + + x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); + if (x != 0) { + x[SZ_DIAG_ERR_MSG - 1] = 0; + pr_info("smem: DIAG '%s'\n", x); + } +} + +/* call when SMSM_RESET flag is set in the A9's smsm_state */ +static void handle_modem_crash(void) +{ + pr_err("ARM9 has CRASHED\n"); + smd_diag(); + + /* hard reboot if possible */ + if (msm_hw_reset_hook) + msm_hw_reset_hook(); + + /* in this case the modem or watchdog should reboot us */ + for (;;) + ; +} + +uint32_t raw_smsm_get_state(enum smsm_state_item item) +{ + return readl(smd_info.state + item * 4); +} + +static int check_for_modem_crash(void) +{ + if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET) { + handle_modem_crash(); + return -1; + } + return 0; +} + +/* the spinlock is used to synchronize between the + * irq handler and code that mutates the channel + * list or fiddles with channel state + */ +DEFINE_SPINLOCK(smd_lock); +DEFINE_SPINLOCK(smem_lock); + +/* the mutex is used during open() and close() + * operations to avoid races while creating or + * destroying smd_channel structures + */ +static DEFINE_MUTEX(smd_creation_mutex); + +static int smd_initialized; + +LIST_HEAD(smd_ch_closed_list); +LIST_HEAD(smd_ch_list_modem); +LIST_HEAD(smd_ch_list_dsp); + +static unsigned char smd_ch_allocated[64]; +static struct work_struct probe_work; + +/* how many bytes are available for reading */ +static int smd_stream_read_avail(struct smd_channel *ch) +{ + return (ch->recv->head - ch->recv->tail) & ch->fifo_mask; +} + +/* how many bytes we are free to write */ +static int smd_stream_write_avail(struct smd_channel *ch) +{ + return ch->fifo_mask - + ((ch->send->head - ch->send->tail) & ch->fifo_mask); +} + +static int smd_packet_read_avail(struct smd_channel *ch) +{ + if (ch->current_packet) { + int n = smd_stream_read_avail(ch); + if (n > ch->current_packet) + n = ch->current_packet; + return n; + } else { + return 0; + } +} + +static int smd_packet_write_avail(struct smd_channel *ch) +{ + int n = smd_stream_write_avail(ch); + return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0; +} + +static int ch_is_open(struct smd_channel *ch) +{ + return (ch->recv->state == SMD_SS_OPENED) && + (ch->send->state == SMD_SS_OPENED); +} + +/* provide a pointer and length to readable data in the fifo */ +static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr) +{ + unsigned head = ch->recv->head; + unsigned tail = ch->recv->tail; + *ptr = (void *) (ch->recv_data + tail); + + if (tail <= head) + return head - tail; + else + return ch->fifo_size - tail; +} + +/* advance the fifo read pointer after data from ch_read_buffer is consumed */ +static void ch_read_done(struct smd_channel *ch, unsigned count) +{ + BUG_ON(count > smd_stream_read_avail(ch)); + ch->recv->tail = (ch->recv->tail + count) & ch->fifo_mask; + ch->send->fTAIL = 1; +} + +/* basic read interface to ch_read_{buffer,done} used + * by smd_*_read() and update_packet_state() + * will read-and-discard if the _data pointer is null + */ +static int ch_read(struct smd_channel *ch, void *_data, int len) +{ + void *ptr; + unsigned n; + unsigned char *data = _data; + int orig_len = len; + + while (len > 0) { + n = ch_read_buffer(ch, &ptr); + if (n == 0) + break; + + if (n > len) + n = len; + if (_data) + memcpy(data, ptr, n); + + data += n; + len -= n; + ch_read_done(ch, n); + } + + return orig_len - len; +} + +static void update_stream_state(struct smd_channel *ch) +{ + /* streams have no special state requiring updating */ +} + +static void update_packet_state(struct smd_channel *ch) +{ + unsigned hdr[5]; + int r; + + /* can't do anything if we're in the middle of a packet */ + if (ch->current_packet != 0) + return; + + /* don't bother unless we can get the full header */ + if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) + return; + + r = ch_read(ch, hdr, SMD_HEADER_SIZE); + BUG_ON(r != SMD_HEADER_SIZE); + + ch->current_packet = hdr[0]; +} + +/* provide a pointer and length to next free space in the fifo */ +static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) +{ + unsigned head = ch->send->head; + unsigned tail = ch->send->tail; + *ptr = (void *) (ch->send_data + head); + + if (head < tail) { + return tail - head - 1; + } else { + if (tail == 0) + return ch->fifo_size - head - 1; + else + return ch->fifo_size - head; + } +} + +/* advace the fifo write pointer after freespace + * from ch_write_buffer is filled + */ +static void ch_write_done(struct smd_channel *ch, unsigned count) +{ + BUG_ON(count > smd_stream_write_avail(ch)); + ch->send->head = (ch->send->head + count) & ch->fifo_mask; + ch->send->fHEAD = 1; +} + +static void ch_set_state(struct smd_channel *ch, unsigned n) +{ + if (n == SMD_SS_OPENED) { + ch->send->fDSR = 1; + ch->send->fCTS = 1; + ch->send->fCD = 1; + } else { + ch->send->fDSR = 0; + ch->send->fCTS = 0; + ch->send->fCD = 0; + } + ch->send->state = n; + ch->send->fSTATE = 1; + ch->notify_other_cpu(); +} + +static void do_smd_probe(void) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + if (shared->heap_info.free_offset != last_heap_free) { + last_heap_free = shared->heap_info.free_offset; + schedule_work(&probe_work); + } +} + +static void smd_state_change(struct smd_channel *ch, + unsigned last, unsigned next) +{ + ch->last_state = next; + + pr_info("SMD: ch %d %d -> %d\n", ch->n, last, next); + + switch (next) { + case SMD_SS_OPENING: + ch->recv->tail = 0; + case SMD_SS_OPENED: + if (ch->send->state != SMD_SS_OPENED) + ch_set_state(ch, SMD_SS_OPENED); + ch->notify(ch->priv, SMD_EVENT_OPEN); + break; + case SMD_SS_FLUSHING: + case SMD_SS_RESET: + /* we should force them to close? */ + default: + ch->notify(ch->priv, SMD_EVENT_CLOSE); + } +} + +static void handle_smd_irq(struct list_head *list, void (*notify)(void)) +{ + unsigned long flags; + struct smd_channel *ch; + int do_notify = 0; + unsigned ch_flags; + unsigned tmp; + + spin_lock_irqsave(&smd_lock, flags); + list_for_each_entry(ch, list, ch_list) { + ch_flags = 0; + if (ch_is_open(ch)) { + if (ch->recv->fHEAD) { + ch->recv->fHEAD = 0; + ch_flags |= 1; + do_notify |= 1; + } + if (ch->recv->fTAIL) { + ch->recv->fTAIL = 0; + ch_flags |= 2; + do_notify |= 1; + } + if (ch->recv->fSTATE) { + ch->recv->fSTATE = 0; + ch_flags |= 4; + do_notify |= 1; + } + } + tmp = ch->recv->state; + if (tmp != ch->last_state) + smd_state_change(ch, ch->last_state, tmp); + if (ch_flags) { + ch->update_state(ch); + ch->notify(ch->priv, SMD_EVENT_DATA); + } + } + if (do_notify) + notify(); + spin_unlock_irqrestore(&smd_lock, flags); + do_smd_probe(); +} + +static irqreturn_t smd_modem_irq_handler(int irq, void *data) +{ + handle_smd_irq(&smd_ch_list_modem, notify_modem_smd); + return IRQ_HANDLED; +} + +#if defined(CONFIG_QDSP6) +static irqreturn_t smd_dsp_irq_handler(int irq, void *data) +{ + handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd); + return IRQ_HANDLED; +} +#endif + +static void smd_fake_irq_handler(unsigned long arg) +{ + handle_smd_irq(&smd_ch_list_modem, notify_modem_smd); + handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd); +} + +static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0); + +static inline int smd_need_int(struct smd_channel *ch) +{ + if (ch_is_open(ch)) { + if (ch->recv->fHEAD || ch->recv->fTAIL || ch->recv->fSTATE) + return 1; + if (ch->recv->state != ch->last_state) + return 1; + } + return 0; +} + +void smd_sleep_exit(void) +{ + unsigned long flags; + struct smd_channel *ch; + int need_int = 0; + + spin_lock_irqsave(&smd_lock, flags); + list_for_each_entry(ch, &smd_ch_list_modem, ch_list) { + if (smd_need_int(ch)) { + need_int = 1; + break; + } + } + list_for_each_entry(ch, &smd_ch_list_dsp, ch_list) { + if (smd_need_int(ch)) { + need_int = 1; + break; + } + } + spin_unlock_irqrestore(&smd_lock, flags); + do_smd_probe(); + + if (need_int) { + if (msm_smd_debug_mask & MSM_SMD_DEBUG) + pr_info("smd_sleep_exit need interrupt\n"); + tasklet_schedule(&smd_fake_irq_tasklet); + } +} + + +void smd_kick(smd_channel_t *ch) +{ + unsigned long flags; + unsigned tmp; + + spin_lock_irqsave(&smd_lock, flags); + ch->update_state(ch); + tmp = ch->recv->state; + if (tmp != ch->last_state) { + ch->last_state = tmp; + if (tmp == SMD_SS_OPENED) + ch->notify(ch->priv, SMD_EVENT_OPEN); + else + ch->notify(ch->priv, SMD_EVENT_CLOSE); + } + ch->notify(ch->priv, SMD_EVENT_DATA); + ch->notify_other_cpu(); + spin_unlock_irqrestore(&smd_lock, flags); +} + +static int smd_is_packet(int chn, unsigned type) +{ + type &= SMD_KIND_MASK; + if (type == SMD_KIND_PACKET) + return 1; + if (type == SMD_KIND_STREAM) + return 0; + + /* older AMSS reports SMD_KIND_UNKNOWN always */ + if ((chn > 4) || (chn == 1)) + return 1; + else + return 0; +} + +static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) +{ + void *ptr; + const unsigned char *buf = _data; + unsigned xfer; + int orig_len = len; + + if (len < 0) + return -EINVAL; + + while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { + if (!ch_is_open(ch)) + break; + if (xfer > len) + xfer = len; + memcpy(ptr, buf, xfer); + ch_write_done(ch, xfer); + len -= xfer; + buf += xfer; + if (len == 0) + break; + } + + ch->notify_other_cpu(); + + return orig_len - len; +} + +static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) +{ + unsigned hdr[5]; + + if (len < 0) + return -EINVAL; + + if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE)) + return -ENOMEM; + + hdr[0] = len; + hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0; + + smd_stream_write(ch, hdr, sizeof(hdr)); + smd_stream_write(ch, _data, len); + + return len; +} + +static int smd_stream_read(smd_channel_t *ch, void *data, int len) +{ + int r; + + if (len < 0) + return -EINVAL; + + r = ch_read(ch, data, len); + if (r > 0) + ch->notify_other_cpu(); + + return r; +} + +static int smd_packet_read(smd_channel_t *ch, void *data, int len) +{ + unsigned long flags; + int r; + + if (len < 0) + return -EINVAL; + + if (len > ch->current_packet) + len = ch->current_packet; + + r = ch_read(ch, data, len); + if (r > 0) + ch->notify_other_cpu(); + + spin_lock_irqsave(&smd_lock, flags); + ch->current_packet -= r; + update_packet_state(ch); + spin_unlock_irqrestore(&smd_lock, flags); + + return r; +} + +static int smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) +{ + struct smd_channel *ch; + + ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); + if (ch == 0) { + pr_err("smd_alloc_channel() out of memory\n"); + return -1; + } + ch->n = cid; + + if (_smd_alloc_channel(ch)) { + kfree(ch); + return -1; + } + + ch->fifo_mask = ch->fifo_size - 1; + ch->type = type; + + if ((type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM) + ch->notify_other_cpu = notify_modem_smd; + else + ch->notify_other_cpu = notify_dsp_smd; + + if (smd_is_packet(cid, type)) { + ch->read = smd_packet_read; + ch->write = smd_packet_write; + ch->read_avail = smd_packet_read_avail; + ch->write_avail = smd_packet_write_avail; + ch->update_state = update_packet_state; + } else { + ch->read = smd_stream_read; + ch->write = smd_stream_write; + ch->read_avail = smd_stream_read_avail; + ch->write_avail = smd_stream_write_avail; + ch->update_state = update_stream_state; + } + + if ((type & 0xff) == 0) + memcpy(ch->name, "SMD_", 4); + else + memcpy(ch->name, "DSP_", 4); + memcpy(ch->name + 4, name, 20); + ch->name[23] = 0; + ch->pdev.name = ch->name; + ch->pdev.id = -1; + + pr_info("smd_alloc_channel() cid=%02d size=%05d '%s'\n", + ch->n, ch->fifo_size, ch->name); + + mutex_lock(&smd_creation_mutex); + list_add(&ch->ch_list, &smd_ch_closed_list); + mutex_unlock(&smd_creation_mutex); + + platform_device_register(&ch->pdev); + return 0; +} + +static void smd_channel_probe_worker(struct work_struct *work) +{ + struct smd_alloc_elm *shared; + unsigned ctype; + unsigned type; + unsigned n; + + shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); + if (!shared) { + pr_err("smd: cannot find allocation table\n"); + return; + } + for (n = 0; n < 64; n++) { + if (smd_ch_allocated[n]) + continue; + if (!shared[n].ref_count) + continue; + if (!shared[n].name[0]) + continue; + ctype = shared[n].ctype; + type = ctype & SMD_TYPE_MASK; + + /* DAL channels are stream but neither the modem, + * nor the DSP correctly indicate this. Fixup manually. + */ + if (!memcmp(shared[n].name, "DAL", 3)) + ctype = (ctype & (~SMD_KIND_MASK)) | SMD_KIND_STREAM; + + type = shared[n].ctype & SMD_TYPE_MASK; + if ((type == SMD_TYPE_APPS_MODEM) || + (type == SMD_TYPE_APPS_DSP)) + if (!smd_alloc_channel(shared[n].name, shared[n].cid, ctype)) + smd_ch_allocated[n] = 1; + } +} + +static void do_nothing_notify(void *priv, unsigned flags) +{ +} + +struct smd_channel *smd_get_channel(const char *name) +{ + struct smd_channel *ch; + + mutex_lock(&smd_creation_mutex); + list_for_each_entry(ch, &smd_ch_closed_list, ch_list) { + if (!strcmp(name, ch->name)) { + list_del(&ch->ch_list); + mutex_unlock(&smd_creation_mutex); + return ch; + } + } + mutex_unlock(&smd_creation_mutex); + + return NULL; +} + +int smd_open(const char *name, smd_channel_t **_ch, + void *priv, void (*notify)(void *, unsigned)) +{ + struct smd_channel *ch; + unsigned long flags; + + if (smd_initialized == 0) { + pr_info("smd_open() before smd_init()\n"); + return -ENODEV; + } + + ch = smd_get_channel(name); + if (!ch) + return -ENODEV; + + if (notify == 0) + notify = do_nothing_notify; + + ch->notify = notify; + ch->current_packet = 0; + ch->last_state = SMD_SS_CLOSED; + ch->priv = priv; + + *_ch = ch; + + spin_lock_irqsave(&smd_lock, flags); + + if ((ch->type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM) + list_add(&ch->ch_list, &smd_ch_list_modem); + else + list_add(&ch->ch_list, &smd_ch_list_dsp); + + /* If the remote side is CLOSING, we need to get it to + * move to OPENING (which we'll do by moving from CLOSED to + * OPENING) and then get it to move from OPENING to + * OPENED (by doing the same state change ourselves). + * + * Otherwise, it should be OPENING and we can move directly + * to OPENED so that it will follow. + */ + if (ch->recv->state == SMD_SS_CLOSING) { + ch->send->head = 0; + ch_set_state(ch, SMD_SS_OPENING); + } else { + ch_set_state(ch, SMD_SS_OPENED); + } + spin_unlock_irqrestore(&smd_lock, flags); + smd_kick(ch); + + return 0; +} + +int smd_close(smd_channel_t *ch) +{ + unsigned long flags; + + pr_info("smd_close(%p)\n", ch); + + if (ch == 0) + return -1; + + spin_lock_irqsave(&smd_lock, flags); + ch->notify = do_nothing_notify; + list_del(&ch->ch_list); + ch_set_state(ch, SMD_SS_CLOSED); + spin_unlock_irqrestore(&smd_lock, flags); + + mutex_lock(&smd_creation_mutex); + list_add(&ch->ch_list, &smd_ch_closed_list); + mutex_unlock(&smd_creation_mutex); + + return 0; +} + +int smd_read(smd_channel_t *ch, void *data, int len) +{ + return ch->read(ch, data, len); +} + +int smd_write(smd_channel_t *ch, const void *data, int len) +{ + return ch->write(ch, data, len); +} + +int smd_write_atomic(smd_channel_t *ch, const void *data, int len) +{ + unsigned long flags; + int res; + spin_lock_irqsave(&smd_lock, flags); + res = ch->write(ch, data, len); + spin_unlock_irqrestore(&smd_lock, flags); + return res; +} + +int smd_read_avail(smd_channel_t *ch) +{ + return ch->read_avail(ch); +} + +int smd_write_avail(smd_channel_t *ch) +{ + return ch->write_avail(ch); +} + +int smd_wait_until_readable(smd_channel_t *ch, int bytes) +{ + return -1; +} + +int smd_wait_until_writable(smd_channel_t *ch, int bytes) +{ + return -1; +} + +int smd_cur_packet_size(smd_channel_t *ch) +{ + return ch->current_packet; +} + + +/* ------------------------------------------------------------------------- */ + +void *smem_alloc(unsigned id, unsigned size) +{ + return smem_find(id, size); +} + +void *smem_item(unsigned id, unsigned *size) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + struct smem_heap_entry *toc = shared->heap_toc; + + if (id >= SMEM_NUM_ITEMS) + return 0; + + if (toc[id].allocated) { + *size = toc[id].size; + return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset); + } else { + *size = 0; + } + + return 0; +} + +void *smem_find(unsigned id, unsigned size_in) +{ + unsigned size; + void *ptr; + + ptr = smem_item(id, &size); + if (!ptr) + return 0; + + size_in = ALIGN(size_in, 8); + if (size_in != size) { + pr_err("smem_find(%d, %d): wrong size %d\n", + id, size_in, size); + return 0; + } + + return ptr; +} + +static irqreturn_t smsm_irq_handler(int irq, void *data) +{ + unsigned long flags; + unsigned apps, modm; + + spin_lock_irqsave(&smem_lock, flags); + + apps = raw_smsm_get_state(SMSM_STATE_APPS); + modm = raw_smsm_get_state(SMSM_STATE_MODEM); + + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("<SM %08x %08x>\n", apps, modm); + if (modm & SMSM_RESET) + handle_modem_crash(); + + do_smd_probe(); + + spin_unlock_irqrestore(&smem_lock, flags); + return IRQ_HANDLED; +} + +int smsm_change_state(enum smsm_state_item item, + uint32_t clear_mask, uint32_t set_mask) +{ + unsigned long addr = smd_info.state + item * 4; + unsigned long flags; + unsigned state; + + if (!smd_info.ready) + return -EIO; + + spin_lock_irqsave(&smem_lock, flags); + + if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET) + handle_modem_crash(); + + state = (readl(addr) & ~clear_mask) | set_mask; + writel(state, addr); + + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("smsm_change_state %d %x\n", item, state); + notify_other_smsm(); + + spin_unlock_irqrestore(&smem_lock, flags); + + return 0; +} + +uint32_t smsm_get_state(enum smsm_state_item item) +{ + unsigned long flags; + uint32_t rv; + + spin_lock_irqsave(&smem_lock, flags); + + rv = readl(smd_info.state + item * 4); + + if (item == SMSM_STATE_MODEM && (rv & SMSM_RESET)) + handle_modem_crash(); + + spin_unlock_irqrestore(&smem_lock, flags); + + return rv; +} + +#ifdef CONFIG_ARCH_MSM_SCORPION + +int smsm_set_sleep_duration(uint32_t delay) +{ + struct msm_dem_slave_data *ptr; + + ptr = smem_find(SMEM_APPS_DEM_SLAVE_DATA, sizeof(*ptr)); + if (ptr == NULL) { + pr_err("smsm_set_sleep_duration <SM NO APPS_DEM_SLAVE_DATA>\n"); + return -EIO; + } + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("smsm_set_sleep_duration %d -> %d\n", + ptr->sleep_time, delay); + ptr->sleep_time = delay; + return 0; +} + +#else + +int smsm_set_sleep_duration(uint32_t delay) +{ + uint32_t *ptr; + + ptr = smem_find(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); + if (ptr == NULL) { + pr_err("smsm_set_sleep_duration <SM NO SLEEP_DELAY>\n"); + return -EIO; + } + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("smsm_set_sleep_duration %d -> %d\n", + *ptr, delay); + *ptr = delay; + return 0; +} + +#endif + +int smd_core_init(void) +{ + int r; + pr_info("smd_core_init()\n"); + + /* wait for essential items to be initialized */ + for (;;) { + unsigned size; + void *state; + state = smem_item(SMEM_SMSM_SHARED_STATE, &size); + if (size == SMSM_V1_SIZE || size == SMSM_V2_SIZE) { + smd_info.state = (unsigned)state; + break; + } + } + + smd_info.ready = 1; + + r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler, + IRQF_TRIGGER_RISING, "smd_dev", 0); + if (r < 0) + return r; + r = enable_irq_wake(INT_A9_M2A_0); + if (r < 0) + pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n"); + + r = request_irq(INT_A9_M2A_5, smsm_irq_handler, + IRQF_TRIGGER_RISING, "smsm_dev", 0); + if (r < 0) { + free_irq(INT_A9_M2A_0, 0); + return r; + } + r = enable_irq_wake(INT_A9_M2A_5); + if (r < 0) + pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); + +#if defined(CONFIG_QDSP6) + r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler, + IRQF_TRIGGER_RISING, "smd_dsp", 0); + if (r < 0) { + free_irq(INT_A9_M2A_0, 0); + free_irq(INT_A9_M2A_5, 0); + return r; + } +#endif + + /* check for any SMD channels that may already exist */ + do_smd_probe(); + + /* indicate that we're up and running */ + smsm_change_state(SMSM_STATE_APPS, + ~0, SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT | SMSM_RUN); +#ifdef CONFIG_ARCH_MSM_SCORPION + smsm_change_state(SMSM_STATE_APPS_DEM, ~0, 0); +#endif + + pr_info("smd_core_init() done\n"); + + return 0; +} + +static int __init msm_smd_probe(struct platform_device *pdev) +{ + pr_info("smd_init()\n"); + + /* + * If we haven't waited for the ARM9 to boot up till now, + * then we need to wait here. Otherwise this should just + * return immediately. + */ + proc_comm_boot_wait(); + + INIT_WORK(&probe_work, smd_channel_probe_worker); + + if (smd_core_init()) { + pr_err("smd_core_init() failed\n"); + return -1; + } + + do_smd_probe(); + + msm_check_for_modem_crash = check_for_modem_crash; + + msm_init_last_radio_log(THIS_MODULE); + + smd_initialized = 1; + + return 0; +} + +static struct platform_driver msm_smd_driver = { + .probe = msm_smd_probe, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_smd_init(void) +{ + return platform_driver_register(&msm_smd_driver); +} + +module_init(msm_smd_init); + +MODULE_DESCRIPTION("MSM Shared Memory Core"); +MODULE_AUTHOR("Brian Swetland <swetland@google.com>"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c new file mode 100644 index 000000000000..3b2dd717b788 --- /dev/null +++ b/arch/arm/mach-msm/smd_debug.c @@ -0,0 +1,315 @@ +/* arch/arm/mach-msm/smd_debug.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/debugfs.h> +#include <linux/list.h> + +#include <mach/msm_iomap.h> + +#include "smd_private.h" + +#if defined(CONFIG_DEBUG_FS) + +static char *chstate(unsigned n) +{ + switch (n) { + case SMD_SS_CLOSED: + return "CLOSED"; + case SMD_SS_OPENING: + return "OPENING"; + case SMD_SS_OPENED: + return "OPENED"; + case SMD_SS_FLUSHING: + return "FLUSHING"; + case SMD_SS_CLOSING: + return "CLOSING"; + case SMD_SS_RESET: + return "RESET"; + case SMD_SS_RESET_OPENING: + return "ROPENING"; + default: + return "UNKNOWN"; + } +} + + +static int dump_ch(char *buf, int max, struct smd_channel *ch) +{ + volatile struct smd_half_channel *s = ch->send; + volatile struct smd_half_channel *r = ch->recv; + + return scnprintf( + buf, max, + "ch%02d:" + " %8s(%05d/%05d) %c%c%c%c%c%c%c <->" + " %8s(%05d/%05d) %c%c%c%c%c%c%c '%s'\n", ch->n, + chstate(s->state), s->tail, s->head, + s->fDSR ? 'D' : 'd', + s->fCTS ? 'C' : 'c', + s->fCD ? 'C' : 'c', + s->fRI ? 'I' : 'i', + s->fHEAD ? 'W' : 'w', + s->fTAIL ? 'R' : 'r', + s->fSTATE ? 'S' : 's', + chstate(r->state), r->tail, r->head, + r->fDSR ? 'D' : 'd', + r->fCTS ? 'R' : 'r', + r->fCD ? 'C' : 'c', + r->fRI ? 'I' : 'i', + r->fHEAD ? 'W' : 'w', + r->fTAIL ? 'R' : 'r', + r->fSTATE ? 'S' : 's', + ch->name + ); +} + +static int debug_read_stat(char *buf, int max) +{ + char *msg; + int i = 0; + + msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); + + if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET) + i += scnprintf(buf + i, max - i, + "smsm: ARM9 HAS CRASHED\n"); + + i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n", + raw_smsm_get_state(SMSM_STATE_MODEM), + raw_smsm_get_state(SMSM_STATE_APPS)); +#ifdef CONFIG_ARCH_MSM_SCORPION + i += scnprintf(buf + i, max - i, "smsm dem: apps: %08x modem: %08x " + "qdsp6: %08x power: %08x time: %08x\n", + raw_smsm_get_state(SMSM_STATE_APPS_DEM), + raw_smsm_get_state(SMSM_STATE_MODEM_DEM), + raw_smsm_get_state(SMSM_STATE_QDSP6_DEM), + raw_smsm_get_state(SMSM_STATE_POWER_MASTER_DEM), + raw_smsm_get_state(SMSM_STATE_TIME_MASTER_DEM)); +#endif + if (msg) { + msg[SZ_DIAG_ERR_MSG - 1] = 0; + i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg); + } + return i; +} + +static int debug_read_mem(char *buf, int max) +{ + unsigned n; + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + struct smem_heap_entry *toc = shared->heap_toc; + int i = 0; + + i += scnprintf(buf + i, max - i, + "heap: init=%d free=%d remain=%d\n", + shared->heap_info.initialized, + shared->heap_info.free_offset, + shared->heap_info.heap_remaining); + + for (n = 0; n < SMEM_NUM_ITEMS; n++) { + if (toc[n].allocated == 0) + continue; + i += scnprintf(buf + i, max - i, + "%04d: offset %08x size %08x\n", + n, toc[n].offset, toc[n].size); + } + return i; +} + +static int debug_read_ch(char *buf, int max) +{ + struct smd_channel *ch; + unsigned long flags; + int i = 0; + + spin_lock_irqsave(&smd_lock, flags); + list_for_each_entry(ch, &smd_ch_list_dsp, ch_list) + i += dump_ch(buf + i, max - i, ch); + list_for_each_entry(ch, &smd_ch_list_modem, ch_list) + i += dump_ch(buf + i, max - i, ch); + list_for_each_entry(ch, &smd_ch_closed_list, ch_list) + i += dump_ch(buf + i, max - i, ch); + spin_unlock_irqrestore(&smd_lock, flags); + + return i; +} + +static int debug_read_version(char *buf, int max) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + unsigned version = shared->version[VERSION_MODEM]; + return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff); +} + +static int debug_read_build_id(char *buf, int max) +{ + unsigned size; + void *data; + + data = smem_item(SMEM_HW_SW_BUILD_ID, &size); + if (!data) + return 0; + + if (size >= max) + size = max; + memcpy(buf, data, size); + + return size; +} + +static int debug_read_alloc_tbl(char *buf, int max) +{ + struct smd_alloc_elm *shared; + int n, i = 0; + + shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); + + for (n = 0; n < 64; n++) { + if (shared[n].ref_count == 0) + continue; + i += scnprintf(buf + i, max - i, + "%03d: %-20s cid=%02d type=%03d " + "kind=%02d ref_count=%d\n", + n, shared[n].name, shared[n].cid, + shared[n].ctype & 0xff, + (shared[n].ctype >> 8) & 0xf, + shared[n].ref_count); + } + + return i; +} + +#define DEBUG_BUFMAX 4096 +static char debug_buffer[DEBUG_BUFMAX]; + +static ssize_t debug_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fill)(char *buf, int max) = file->private_data; + int bsize = fill(debug_buffer, DEBUG_BUFMAX); + return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations debug_ops = { + .read = debug_read, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fill)(char *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fill, &debug_ops); +} + +static int smd_debugfs_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("smd", 0); + if (IS_ERR(dent)) + return 1; + + debug_create("ch", 0444, dent, debug_read_ch); + debug_create("stat", 0444, dent, debug_read_stat); + debug_create("mem", 0444, dent, debug_read_mem); + debug_create("version", 0444, dent, debug_read_version); + debug_create("tbl", 0444, dent, debug_read_alloc_tbl); + debug_create("build", 0444, dent, debug_read_build_id); + + return 0; +} + +late_initcall(smd_debugfs_init); +#endif + + +#define MAX_NUM_SLEEP_CLIENTS 64 +#define MAX_SLEEP_NAME_LEN 8 + +#define NUM_GPIO_INT_REGISTERS 6 +#define GPIO_SMEM_NUM_GROUPS 2 +#define GPIO_SMEM_MAX_PC_INTERRUPTS 8 + +struct tramp_gpio_save { + unsigned int enable; + unsigned int detect; + unsigned int polarity; +}; + +struct tramp_gpio_smem { + uint16_t num_fired[GPIO_SMEM_NUM_GROUPS]; + uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS]; + uint32_t enabled[NUM_GPIO_INT_REGISTERS]; + uint32_t detection[NUM_GPIO_INT_REGISTERS]; + uint32_t polarity[NUM_GPIO_INT_REGISTERS]; +}; + + +void smsm_print_sleep_info(void) +{ + unsigned long flags; + uint32_t *ptr; + struct tramp_gpio_smem *gpio; + struct smsm_interrupt_info *int_info; + + + spin_lock_irqsave(&smem_lock, flags); + + ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); + if (ptr) + pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr); + + ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr)); + if (ptr) + pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr); + + ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr)); + if (ptr) + pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr); + +#ifndef CONFIG_ARCH_MSM_SCORPION + int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); + if (int_info) + pr_info("SMEM_SMSM_INT_INFO %x %x %x\n", + int_info->interrupt_mask, + int_info->pending_interrupts, + int_info->wakeup_reason); + + gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio)); + if (gpio) { + int i; + for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++) + pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n", + i, gpio->enabled[i], gpio->detection[i], + gpio->polarity[i]); + + for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) + pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n", + i, gpio->num_fired[i], gpio->fired[i][0], + gpio->fired[i][1]); + } +#else +#endif + spin_unlock_irqrestore(&smem_lock, flags); +} + diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h new file mode 100644 index 000000000000..727bfe68aa9b --- /dev/null +++ b/arch/arm/mach-msm/smd_private.h @@ -0,0 +1,403 @@ +/* arch/arm/mach-msm/smd_private.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_ +#define _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_ + +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/io.h> + +#include <mach/msm_iomap.h> + +struct smem_heap_info { + unsigned initialized; + unsigned free_offset; + unsigned heap_remaining; + unsigned reserved; +}; + +struct smem_heap_entry { + unsigned allocated; + unsigned offset; + unsigned size; + unsigned reserved; +}; + +struct smem_proc_comm { + unsigned command; + unsigned status; + unsigned data1; + unsigned data2; +}; + +#define PC_APPS 0 +#define PC_MODEM 1 + +#define VERSION_SMD 0 +#define VERSION_QDSP6 4 +#define VERSION_APPS_SBL 6 +#define VERSION_MODEM_SBL 7 +#define VERSION_APPS 8 +#define VERSION_MODEM 9 + +struct smem_shared { + struct smem_proc_comm proc_comm[4]; + unsigned version[32]; + struct smem_heap_info heap_info; + struct smem_heap_entry heap_toc[512]; +}; + +#define SMSM_V1_SIZE (sizeof(unsigned) * 8) +#define SMSM_V2_SIZE (sizeof(unsigned) * 4) + +#ifdef CONFIG_MSM_SMD_PKG3 +struct smsm_interrupt_info { + uint32_t interrupt_mask; + uint32_t pending_interrupts; + uint32_t wakeup_reason; +}; +#else +#define DEM_MAX_PORT_NAME_LEN (20) +struct msm_dem_slave_data { + uint32_t sleep_time; + uint32_t interrupt_mask; + uint32_t resources_used; + uint32_t reserved1; + + uint32_t wakeup_reason; + uint32_t pending_interrupts; + uint32_t rpc_prog; + uint32_t rpc_proc; + char smd_port_name[DEM_MAX_PORT_NAME_LEN]; + uint32_t reserved2; +}; +#endif + +#define SZ_DIAG_ERR_MSG 0xC8 +#define ID_DIAG_ERR_MSG SMEM_DIAG_ERR_MESSAGE +#define ID_SMD_CHANNELS SMEM_SMD_BASE_ID +#define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE +#define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL + +#define SMSM_INIT 0x00000001 +#define SMSM_SMDINIT 0x00000008 +#define SMSM_RPCINIT 0x00000020 +#define SMSM_RESET 0x00000040 +#define SMSM_RSA 0x00000080 +#define SMSM_RUN 0x00000100 +#define SMSM_PWRC 0x00000200 +#define SMSM_TIMEWAIT 0x00000400 +#define SMSM_TIMEINIT 0x00000800 +#define SMSM_PWRC_EARLY_EXIT 0x00001000 +#define SMSM_WFPI 0x00002000 +#define SMSM_SLEEP 0x00004000 +#define SMSM_SLEEPEXIT 0x00008000 +#define SMSM_APPS_REBOOT 0x00020000 +#define SMSM_SYSTEM_POWER_DOWN 0x00040000 +#define SMSM_SYSTEM_REBOOT 0x00080000 +#define SMSM_SYSTEM_DOWNLOAD 0x00100000 +#define SMSM_PWRC_SUSPEND 0x00200000 +#define SMSM_APPS_SHUTDOWN 0x00400000 +#define SMSM_SMD_LOOPBACK 0x00800000 +#define SMSM_RUN_QUIET 0x01000000 +#define SMSM_MODEM_WAIT 0x02000000 +#define SMSM_MODEM_BREAK 0x04000000 +#define SMSM_MODEM_CONTINUE 0x08000000 +#define SMSM_UNKNOWN 0x80000000 + +#define SMSM_WKUP_REASON_RPC 0x00000001 +#define SMSM_WKUP_REASON_INT 0x00000002 +#define SMSM_WKUP_REASON_GPIO 0x00000004 +#define SMSM_WKUP_REASON_TIMER 0x00000008 +#define SMSM_WKUP_REASON_ALARM 0x00000010 +#define SMSM_WKUP_REASON_RESET 0x00000020 + +#ifdef CONFIG_ARCH_MSM7X00A +enum smsm_state_item { + SMSM_STATE_APPS = 1, + SMSM_STATE_MODEM = 3, + SMSM_STATE_COUNT, +}; +#else +enum smsm_state_item { + SMSM_STATE_APPS, + SMSM_STATE_MODEM, + SMSM_STATE_HEXAGON, + SMSM_STATE_APPS_DEM, + SMSM_STATE_MODEM_DEM, + SMSM_STATE_QDSP6_DEM, + SMSM_STATE_POWER_MASTER_DEM, + SMSM_STATE_TIME_MASTER_DEM, + SMSM_STATE_COUNT, +}; +#endif + +void *smem_alloc(unsigned id, unsigned size); +int smsm_change_state(enum smsm_state_item item, uint32_t clear_mask, uint32_t set_mask); +uint32_t smsm_get_state(enum smsm_state_item item); +int smsm_set_sleep_duration(uint32_t delay); +void smsm_print_sleep_info(void); + +#define SMEM_NUM_SMD_CHANNELS 64 + +typedef enum { + /* fixed items */ + SMEM_PROC_COMM = 0, + SMEM_HEAP_INFO, + SMEM_ALLOCATION_TABLE, + SMEM_VERSION_INFO, + SMEM_HW_RESET_DETECT, + SMEM_AARM_WARM_BOOT, + SMEM_DIAG_ERR_MESSAGE, + SMEM_SPINLOCK_ARRAY, + SMEM_MEMORY_BARRIER_LOCATION, + + /* dynamic items */ + SMEM_AARM_PARTITION_TABLE, + SMEM_AARM_BAD_BLOCK_TABLE, + SMEM_RESERVE_BAD_BLOCKS, + SMEM_WM_UUID, + SMEM_CHANNEL_ALLOC_TBL, + SMEM_SMD_BASE_ID, + SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_CHANNELS, + SMEM_SMEM_LOG_EVENTS, + SMEM_SMEM_STATIC_LOG_IDX, + SMEM_SMEM_STATIC_LOG_EVENTS, + SMEM_SMEM_SLOW_CLOCK_SYNC, + SMEM_SMEM_SLOW_CLOCK_VALUE, + SMEM_BIO_LED_BUF, + SMEM_SMSM_SHARED_STATE, + SMEM_SMSM_INT_INFO, + SMEM_SMSM_SLEEP_DELAY, + SMEM_SMSM_LIMIT_SLEEP, + SMEM_SLEEP_POWER_COLLAPSE_DISABLED, + SMEM_KEYPAD_KEYS_PRESSED, + SMEM_KEYPAD_STATE_UPDATED, + SMEM_KEYPAD_STATE_IDX, + SMEM_GPIO_INT, + SMEM_MDDI_LCD_IDX, + SMEM_MDDI_HOST_DRIVER_STATE, + SMEM_MDDI_LCD_DISP_STATE, + SMEM_LCD_CUR_PANEL, + SMEM_MARM_BOOT_SEGMENT_INFO, + SMEM_AARM_BOOT_SEGMENT_INFO, + SMEM_SLEEP_STATIC, + SMEM_SCORPION_FREQUENCY, + SMEM_SMD_PROFILES, + SMEM_TSSC_BUSY, + SMEM_HS_SUSPEND_FILTER_INFO, + SMEM_BATT_INFO, + SMEM_APPS_BOOT_MODE, + SMEM_VERSION_FIRST, + SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24, + SMEM_OSS_RRCASN1_BUF1, + SMEM_OSS_RRCASN1_BUF2, + SMEM_ID_VENDOR0, + SMEM_ID_VENDOR1, + SMEM_ID_VENDOR2, + SMEM_HW_SW_BUILD_ID, + SMEM_SMD_BLOCK_PORT_BASE_ID, + SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID + SMEM_NUM_SMD_CHANNELS, + SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP + SMEM_NUM_SMD_CHANNELS, + SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP + SMEM_NUM_SMD_CHANNELS, + SMEM_SCLK_CONVERSION, + SMEM_SMD_SMSM_INTR_MUX, + SMEM_SMSM_CPU_INTR_MASK, + SMEM_APPS_DEM_SLAVE_DATA, + SMEM_QDSP6_DEM_SLAVE_DATA, + SMEM_CLKREGIM_BSP, + SMEM_CLKREGIM_SOURCES, + SMEM_SMD_FIFO_BASE_ID, + SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID + SMEM_NUM_SMD_CHANNELS, + SMEM_POWER_ON_STATUS_INFO, + SMEM_DAL_AREA, + SMEM_SMEM_LOG_POWER_IDX, + SMEM_SMEM_LOG_POWER_WRAP, + SMEM_SMEM_LOG_POWER_EVENTS, + SMEM_ERR_CRASH_LOG, + SMEM_ERR_F3_TRACE_LOG, + SMEM_NUM_ITEMS, +} smem_mem_type; + + +#define SMD_SS_CLOSED 0x00000000 +#define SMD_SS_OPENING 0x00000001 +#define SMD_SS_OPENED 0x00000002 +#define SMD_SS_FLUSHING 0x00000003 +#define SMD_SS_CLOSING 0x00000004 +#define SMD_SS_RESET 0x00000005 +#define SMD_SS_RESET_OPENING 0x00000006 + +#define SMD_BUF_SIZE 8192 +#define SMD_CHANNELS 64 + +#define SMD_HEADER_SIZE 20 + +struct smd_alloc_elm { + char name[20]; + uint32_t cid; + uint32_t ctype; + uint32_t ref_count; +}; + +struct smd_half_channel { + unsigned state; + unsigned char fDSR; + unsigned char fCTS; + unsigned char fCD; + unsigned char fRI; + unsigned char fHEAD; + unsigned char fTAIL; + unsigned char fSTATE; + unsigned char fUNUSED; + unsigned tail; + unsigned head; +} __attribute__(( aligned(4), packed )); + +/* Only used on SMD package v3 on msm7201a */ +struct smd_shared_v1 { + struct smd_half_channel ch0; + unsigned char data0[SMD_BUF_SIZE]; + struct smd_half_channel ch1; + unsigned char data1[SMD_BUF_SIZE]; +}; + +/* Used on SMD package v4 */ +struct smd_shared_v2 { + struct smd_half_channel ch0; + struct smd_half_channel ch1; +}; + +struct smd_channel { + volatile struct smd_half_channel *send; + volatile struct smd_half_channel *recv; + unsigned char *send_data; + unsigned char *recv_data; + + unsigned fifo_mask; + unsigned fifo_size; + unsigned current_packet; + unsigned n; + + struct list_head ch_list; + + void *priv; + void (*notify)(void *priv, unsigned flags); + + int (*read)(struct smd_channel *ch, void *data, int len); + int (*write)(struct smd_channel *ch, const void *data, int len); + int (*read_avail)(struct smd_channel *ch); + int (*write_avail)(struct smd_channel *ch); + + void (*update_state)(struct smd_channel *ch); + unsigned last_state; + void (*notify_other_cpu)(void); + unsigned type; + + char name[32]; + struct platform_device pdev; +}; + +#define SMD_TYPE_MASK 0x0FF +#define SMD_TYPE_APPS_MODEM 0x000 +#define SMD_TYPE_APPS_DSP 0x001 +#define SMD_TYPE_MODEM_DSP 0x002 + +#define SMD_KIND_MASK 0xF00 +#define SMD_KIND_UNKNOWN 0x000 +#define SMD_KIND_STREAM 0x100 +#define SMD_KIND_PACKET 0x200 + +extern struct list_head smd_ch_closed_list; +extern struct list_head smd_ch_list_modem; +extern struct list_head smd_ch_list_dsp; + +extern spinlock_t smd_lock; +extern spinlock_t smem_lock; + +void *smem_find(unsigned id, unsigned size); +void *smem_item(unsigned id, unsigned *size); +uint32_t raw_smsm_get_state(enum smsm_state_item item); + +extern void msm_init_last_radio_log(struct module *); + +#ifdef CONFIG_MSM_SMD_PKG3 +/* + * This allocator assumes an SMD Package v3 which only exists on + * MSM7x00 SoC's. + */ +static inline int _smd_alloc_channel(struct smd_channel *ch) +{ + struct smd_shared_v1 *shared1; + + shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1)); + if (!shared1) { + pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n); + return -1; + } + ch->send = &shared1->ch0; + ch->recv = &shared1->ch1; + ch->send_data = shared1->data0; + ch->recv_data = shared1->data1; + ch->fifo_size = SMD_BUF_SIZE; + return 0; +} +#else +/* + * This allocator assumes an SMD Package v4, the most common + * and the default. + */ +static inline int _smd_alloc_channel(struct smd_channel *ch) +{ + struct smd_shared_v2 *shared2; + void *buffer; + unsigned buffer_sz; + + shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n, sizeof(*shared2)); + buffer = smem_item(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz); + + if (!buffer) + return -1; + + /* buffer must be a power-of-two size */ + if (buffer_sz & (buffer_sz - 1)) + return -1; + + buffer_sz /= 2; + ch->send = &shared2->ch0; + ch->recv = &shared2->ch1; + ch->send_data = buffer; + ch->recv_data = buffer + buffer_sz; + ch->fifo_size = buffer_sz; + return 0; +} +#endif /* CONFIG_MSM_SMD_PKG3 */ + +#if defined(CONFIG_ARCH_MSM7X30) +static inline void msm_a2m_int(uint32_t irq) +{ + writel(1 << irq, MSM_GCC_BASE + 0x8); +} +#else +static inline void msm_a2m_int(uint32_t irq) +{ + writel(1, MSM_CSR_BASE + 0x400 + (irq * 4)); +} +#endif /* CONFIG_ARCH_MSM7X30 */ + + +#endif diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 4855b8ca5101..dec5ca622d7d 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -25,7 +25,9 @@ #include <asm/mach/time.h> #include <mach/msm_iomap.h> +#ifndef MSM_DGT_BASE #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10) +#endif #define MSM_DGT_SHIFT (5) #define TIMER_MATCH_VAL 0x0000 diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index fcb0b9f25684..a9103bc6615f 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/vreg.c * * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland <swetland@google.com> * * This software is licensed under the terms of the GNU General Public @@ -18,6 +19,7 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/debugfs.h> +#include <linux/string.h> #include <mach/vreg.h> #include "proc_comm.h" @@ -25,42 +27,62 @@ struct vreg { const char *name; unsigned id; + int status; + unsigned refcnt; }; -#define VREG(_name, _id) { .name = _name, .id = _id, } +#define VREG(_name, _id, _status, _refcnt) \ + { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt } static struct vreg vregs[] = { - VREG("msma", 0), - VREG("msmp", 1), - VREG("msme1", 2), - VREG("msmc1", 3), - VREG("msmc2", 4), - VREG("gp3", 5), - VREG("msme2", 6), - VREG("gp4", 7), - VREG("gp1", 8), - VREG("tcxo", 9), - VREG("pa", 10), - VREG("rftx", 11), - VREG("rfrx1", 12), - VREG("rfrx2", 13), - VREG("synt", 14), - VREG("wlan", 15), - VREG("usb", 16), - VREG("boost", 17), - VREG("mmc", 18), - VREG("ruim", 19), - VREG("msmc0", 20), - VREG("gp2", 21), - VREG("gp5", 22), - VREG("gp6", 23), - VREG("rf", 24), - VREG("rf_vco", 26), - VREG("mpll", 27), - VREG("s2", 28), - VREG("s3", 29), - VREG("rfubm", 30), - VREG("ncp", 31), + VREG("msma", 0, 0, 0), + VREG("msmp", 1, 0, 0), + VREG("msme1", 2, 0, 0), + VREG("msmc1", 3, 0, 0), + VREG("msmc2", 4, 0, 0), + VREG("gp3", 5, 0, 0), + VREG("msme2", 6, 0, 0), + VREG("gp4", 7, 0, 0), + VREG("gp1", 8, 0, 0), + VREG("tcxo", 9, 0, 0), + VREG("pa", 10, 0, 0), + VREG("rftx", 11, 0, 0), + VREG("rfrx1", 12, 0, 0), + VREG("rfrx2", 13, 0, 0), + VREG("synt", 14, 0, 0), + VREG("wlan", 15, 0, 0), + VREG("usb", 16, 0, 0), + VREG("boost", 17, 0, 0), + VREG("mmc", 18, 0, 0), + VREG("ruim", 19, 0, 0), + VREG("msmc0", 20, 0, 0), + VREG("gp2", 21, 0, 0), + VREG("gp5", 22, 0, 0), + VREG("gp6", 23, 0, 0), + VREG("rf", 24, 0, 0), + VREG("rf_vco", 26, 0, 0), + VREG("mpll", 27, 0, 0), + VREG("s2", 28, 0, 0), + VREG("s3", 29, 0, 0), + VREG("rfubm", 30, 0, 0), + VREG("ncp", 31, 0, 0), + VREG("gp7", 32, 0, 0), + VREG("gp8", 33, 0, 0), + VREG("gp9", 34, 0, 0), + VREG("gp10", 35, 0, 0), + VREG("gp11", 36, 0, 0), + VREG("gp12", 37, 0, 0), + VREG("gp13", 38, 0, 0), + VREG("gp14", 39, 0, 0), + VREG("gp15", 40, 0, 0), + VREG("gp16", 41, 0, 0), + VREG("gp17", 42, 0, 0), + VREG("s4", 43, 0, 0), + VREG("usb2", 44, 0, 0), + VREG("wlan2", 45, 0, 0), + VREG("xo_out", 46, 0, 0), + VREG("lvsw0", 47, 0, 0), + VREG("lvsw1", 48, 0, 0), }; struct vreg *vreg_get(struct device *dev, const char *id) @@ -70,7 +92,7 @@ struct vreg *vreg_get(struct device *dev, const char *id) if (!strcmp(vregs[n].name, id)) return vregs + n; } - return 0; + return ERR_PTR(-ENOENT); } void vreg_put(struct vreg *vreg) @@ -81,20 +103,39 @@ int vreg_enable(struct vreg *vreg) { unsigned id = vreg->id; unsigned enable = 1; - return msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if (vreg->refcnt == 0) + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if ((vreg->refcnt < UINT_MAX) && (!vreg->status)) + vreg->refcnt++; + + return vreg->status; } -void vreg_disable(struct vreg *vreg) +int vreg_disable(struct vreg *vreg) { unsigned id = vreg->id; unsigned enable = 0; - msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if (!vreg->refcnt) + return 0; + + if (vreg->refcnt == 1) + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if (!vreg->status) + vreg->refcnt--; + + return vreg->status; } int vreg_set_level(struct vreg *vreg, unsigned mv) { unsigned id = vreg->id; - return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); + + vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); + return vreg->status; } #if defined(CONFIG_DEBUG_FS) @@ -118,24 +159,59 @@ static int vreg_debug_set(void *data, u64 val) static int vreg_debug_get(void *data, u64 *val) { - return -ENOSYS; + struct vreg *vreg = data; + + if (!vreg->status) + *val = 0; + else + *val = 1; + + return 0; +} + +static int vreg_debug_count_set(void *data, u64 val) +{ + struct vreg *vreg = data; + if (val > UINT_MAX) + val = UINT_MAX; + vreg->refcnt = val; + return 0; +} + +static int vreg_debug_count_get(void *data, u64 *val) +{ + struct vreg *vreg = data; + + *val = vreg->refcnt; + + return 0; } DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get, + vreg_debug_count_set, "%llu\n"); static int __init vreg_debug_init(void) { struct dentry *dent; int n; + char name[32]; + const char *refcnt_name = "_refcnt"; dent = debugfs_create_dir("vreg", 0); if (IS_ERR(dent)) return 0; - for (n = 0; n < ARRAY_SIZE(vregs); n++) + for (n = 0; n < ARRAY_SIZE(vregs); n++) { (void) debugfs_create_file(vregs[n].name, 0644, dent, vregs + n, &vreg_fops); + strlcpy(name, vregs[n].name, sizeof(name)); + strlcat(name, refcnt_name, sizeof(name)); + (void) debugfs_create_file(name, 0644, + dent, vregs + n, &vreg_count_fops); + } + return 0; } |