aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-02-26 17:43:43 -0500
committerOlof Johansson <olof@lixom.net>2012-02-26 17:43:43 -0500
commit0f830e5c902106e7fe51460fd1e3263bea72bf41 (patch)
treeb83090bb272fce3ebda9aac311f2185ce78be7a3 /arch/arm/mach-tegra
parent9335e9199bd059fc4f5e4e6fcfb9fca1d482e460 (diff)
parentbdc93a77da75ee421125896ce4bbd91afff63809 (diff)
Merge branch 'for-3.4/soc-drivers' into for-3.4/t30-smp
Conflicts: arch/arm/mach-tegra/Makefile
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Makefile3
-rw-r--r--arch/arm/mach-tegra/apbio.c145
-rw-r--r--arch/arm/mach-tegra/apbio.h39
-rw-r--r--arch/arm/mach-tegra/board-harmony-power.c15
-rw-r--r--arch/arm/mach-tegra/board-harmony.c2
-rw-r--r--arch/arm/mach-tegra/board-seaboard.c5
-rw-r--r--arch/arm/mach-tegra/common.c20
-rw-r--r--arch/arm/mach-tegra/dma.c128
-rw-r--r--arch/arm/mach-tegra/fuse.c107
-rw-r--r--arch/arm/mach-tegra/fuse.h34
-rw-r--r--arch/arm/mach-tegra/include/mach/debug-macro.S88
-rw-r--r--arch/arm/mach-tegra/include/mach/gpio-tegra.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/irammap.h35
-rw-r--r--arch/arm/mach-tegra/include/mach/uncompress.h118
-rw-r--r--arch/arm/mach-tegra/pmc.c76
-rw-r--r--arch/arm/mach-tegra/pmc.h23
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c2
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.c224
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.h11
19 files changed, 914 insertions, 163 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index fc4ebe35f484..e5373fb94b9a 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -7,6 +7,7 @@ obj-y += clock.o
7obj-y += timer.o 7obj-y += timer.o
8obj-y += pinmux.o 8obj-y += pinmux.o
9obj-y += fuse.o 9obj-y += fuse.o
10obj-y += pmc.o
10obj-$(CONFIG_CPU_IDLE) += cpuidle.o 11obj-$(CONFIG_CPU_IDLE) += cpuidle.o
11obj-$(CONFIG_CPU_IDLE) += sleep.o 12obj-$(CONFIG_CPU_IDLE) += sleep.o
12obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o 13obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o
@@ -18,7 +19,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
18obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o 19obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
19obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o 20obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o
20obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 21obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
21obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o 22obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o apbio.o
22obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o 23obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
23obj-$(CONFIG_TEGRA_PCI) += pcie.o 24obj-$(CONFIG_TEGRA_PCI) += pcie.o
24obj-$(CONFIG_USB_SUPPORT) += usb_phy.o 25obj-$(CONFIG_USB_SUPPORT) += usb_phy.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
new file mode 100644
index 000000000000..e75451e517bd
--- /dev/null
+++ b/arch/arm/mach-tegra/apbio.c
@@ -0,0 +1,145 @@
1/*
2 * Copyright (C) 2010 NVIDIA Corporation.
3 * Copyright (C) 2010 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/io.h>
18#include <linux/dma-mapping.h>
19#include <linux/spinlock.h>
20#include <linux/completion.h>
21#include <linux/sched.h>
22#include <linux/mutex.h>
23
24#include <mach/dma.h>
25#include <mach/iomap.h>
26
27#include "apbio.h"
28
29static DEFINE_MUTEX(tegra_apb_dma_lock);
30
31static struct tegra_dma_channel *tegra_apb_dma;
32static u32 *tegra_apb_bb;
33static dma_addr_t tegra_apb_bb_phys;
34static DECLARE_COMPLETION(tegra_apb_wait);
35
36bool tegra_apb_init(void)
37{
38 struct tegra_dma_channel *ch;
39
40 mutex_lock(&tegra_apb_dma_lock);
41
42 /* Check to see if we raced to setup */
43 if (tegra_apb_dma)
44 goto out;
45
46 ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
47 TEGRA_DMA_SHARED);
48
49 if (!ch)
50 goto out_fail;
51
52 tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
53 &tegra_apb_bb_phys, GFP_KERNEL);
54 if (!tegra_apb_bb) {
55 pr_err("%s: can not allocate bounce buffer\n", __func__);
56 tegra_dma_free_channel(ch);
57 goto out_fail;
58 }
59
60 tegra_apb_dma = ch;
61out:
62 mutex_unlock(&tegra_apb_dma_lock);
63 return true;
64
65out_fail:
66 mutex_unlock(&tegra_apb_dma_lock);
67 return false;
68}
69
70static void apb_dma_complete(struct tegra_dma_req *req)
71{
72 complete(&tegra_apb_wait);
73}
74
75u32 tegra_apb_readl(unsigned long offset)
76{
77 struct tegra_dma_req req;
78 int ret;
79
80 if (!tegra_apb_dma && !tegra_apb_init())
81 return readl(IO_TO_VIRT(offset));
82
83 mutex_lock(&tegra_apb_dma_lock);
84 req.complete = apb_dma_complete;
85 req.to_memory = 1;
86 req.dest_addr = tegra_apb_bb_phys;
87 req.dest_bus_width = 32;
88 req.dest_wrap = 1;
89 req.source_addr = offset;
90 req.source_bus_width = 32;
91 req.source_wrap = 4;
92 req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
93 req.size = 4;
94
95 INIT_COMPLETION(tegra_apb_wait);
96
97 tegra_dma_enqueue_req(tegra_apb_dma, &req);
98
99 ret = wait_for_completion_timeout(&tegra_apb_wait,
100 msecs_to_jiffies(50));
101
102 if (WARN(ret == 0, "apb read dma timed out")) {
103 tegra_dma_dequeue_req(tegra_apb_dma, &req);
104 *(u32 *)tegra_apb_bb = 0;
105 }
106
107 mutex_unlock(&tegra_apb_dma_lock);
108 return *((u32 *)tegra_apb_bb);
109}
110
111void tegra_apb_writel(u32 value, unsigned long offset)
112{
113 struct tegra_dma_req req;
114 int ret;
115
116 if (!tegra_apb_dma && !tegra_apb_init()) {
117 writel(value, IO_TO_VIRT(offset));
118 return;
119 }
120
121 mutex_lock(&tegra_apb_dma_lock);
122 *((u32 *)tegra_apb_bb) = value;
123 req.complete = apb_dma_complete;
124 req.to_memory = 0;
125 req.dest_addr = offset;
126 req.dest_wrap = 4;
127 req.dest_bus_width = 32;
128 req.source_addr = tegra_apb_bb_phys;
129 req.source_bus_width = 32;
130 req.source_wrap = 1;
131 req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
132 req.size = 4;
133
134 INIT_COMPLETION(tegra_apb_wait);
135
136 tegra_dma_enqueue_req(tegra_apb_dma, &req);
137
138 ret = wait_for_completion_timeout(&tegra_apb_wait,
139 msecs_to_jiffies(50));
140
141 if (WARN(ret == 0, "apb write dma timed out"))
142 tegra_dma_dequeue_req(tegra_apb_dma, &req);
143
144 mutex_unlock(&tegra_apb_dma_lock);
145}
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
new file mode 100644
index 000000000000..8b49e8c89a64
--- /dev/null
+++ b/arch/arm/mach-tegra/apbio.h
@@ -0,0 +1,39 @@
1/*
2 * Copyright (C) 2010 NVIDIA Corporation.
3 * Copyright (C) 2010 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16#ifndef __MACH_TEGRA_APBIO_H
17#define __MACH_TEGRA_APBIO_H
18
19#ifdef CONFIG_TEGRA_SYSTEM_DMA
20
21u32 tegra_apb_readl(unsigned long offset);
22void tegra_apb_writel(u32 value, unsigned long offset);
23
24#else
25#include <asm/io.h>
26#include <mach/io.h>
27
28static inline u32 tegra_apb_readl(unsigned long offset)
29{
30 return readl(IO_TO_VIRT(offset));
31}
32
33static inline void tegra_apb_writel(u32 value, unsigned long offset)
34{
35 writel(value, IO_TO_VIRT(offset));
36}
37#endif
38
39#endif
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
index 21d1285731b3..976edfb05912 100644
--- a/arch/arm/mach-tegra/board-harmony-power.c
+++ b/arch/arm/mach-tegra/board-harmony-power.c
@@ -18,18 +18,13 @@
18#include <linux/i2c.h> 18#include <linux/i2c.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/gpio.h> 20#include <linux/gpio.h>
21#include <linux/io.h>
22#include <linux/regulator/machine.h> 21#include <linux/regulator/machine.h>
23#include <linux/mfd/tps6586x.h> 22#include <linux/mfd/tps6586x.h>
24 23
25#include <mach/iomap.h>
26#include <mach/irqs.h> 24#include <mach/irqs.h>
27 25
28#include "board-harmony.h" 26#include "board-harmony.h"
29 27
30#define PMC_CTRL 0x0
31#define PMC_CTRL_INTR_LOW (1 << 17)
32
33static struct regulator_consumer_supply tps658621_ldo0_supply[] = { 28static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
34 REGULATOR_SUPPLY("pex_clk", NULL), 29 REGULATOR_SUPPLY("pex_clk", NULL),
35}; 30};
@@ -114,16 +109,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
114 109
115int __init harmony_regulator_init(void) 110int __init harmony_regulator_init(void)
116{ 111{
117 void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
118 u32 pmc_ctrl;
119
120 /*
121 * Configure the power management controller to trigger PMU
122 * interrupts when low
123 */
124 pmc_ctrl = readl(pmc + PMC_CTRL);
125 writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
126
127 i2c_register_board_info(3, harmony_regulators, 1); 112 i2c_register_board_info(3, harmony_regulators, 1);
128 113
129 return 0; 114 return 0;
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index 789bdc9e8f91..c00aadb01e09 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = {
101static struct i2c_board_info __initdata wm8903_board_info = { 101static struct i2c_board_info __initdata wm8903_board_info = {
102 I2C_BOARD_INFO("wm8903", 0x1a), 102 I2C_BOARD_INFO("wm8903", 0x1a),
103 .platform_data = &harmony_wm8903_pdata, 103 .platform_data = &harmony_wm8903_pdata,
104 .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
105}; 104};
106 105
107static void __init harmony_i2c_init(void) 106static void __init harmony_i2c_init(void)
@@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void)
111 platform_device_register(&tegra_i2c_device3); 110 platform_device_register(&tegra_i2c_device3);
112 platform_device_register(&tegra_i2c_device4); 111 platform_device_register(&tegra_i2c_device4);
113 112
113 wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
114 i2c_register_board_info(0, &wm8903_board_info, 1); 114 i2c_register_board_info(0, &wm8903_board_info, 1);
115} 115}
116 116
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
index ebac65f52510..d669847f0485 100644
--- a/arch/arm/mach-tegra/board-seaboard.c
+++ b/arch/arm/mach-tegra/board-seaboard.c
@@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = {
159 159
160static struct i2c_board_info __initdata isl29018_device = { 160static struct i2c_board_info __initdata isl29018_device = {
161 I2C_BOARD_INFO("isl29018", 0x44), 161 I2C_BOARD_INFO("isl29018", 0x44),
162 .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
163}; 162};
164 163
165static struct i2c_board_info __initdata adt7461_device = { 164static struct i2c_board_info __initdata adt7461_device = {
@@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = {
183static struct i2c_board_info __initdata wm8903_device = { 182static struct i2c_board_info __initdata wm8903_device = {
184 I2C_BOARD_INFO("wm8903", 0x1a), 183 I2C_BOARD_INFO("wm8903", 0x1a),
185 .platform_data = &wm8903_pdata, 184 .platform_data = &wm8903_pdata,
186 .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
187}; 185};
188 186
189static int seaboard_ehci_init(void) 187static int seaboard_ehci_init(void)
@@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void)
214 gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018"); 212 gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
215 gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ); 213 gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
216 214
215 isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
217 i2c_register_board_info(0, &isl29018_device, 1); 216 i2c_register_board_info(0, &isl29018_device, 1);
217
218 wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
218 i2c_register_board_info(0, &wm8903_device, 1); 219 i2c_register_board_info(0, &wm8903_device, 1);
219 220
220 i2c_register_board_info(3, &adt7461_device, 1); 221 i2c_register_board_info(3, &adt7461_device, 1);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 029558114236..1cdcda13a0f7 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -32,6 +32,24 @@
32#include "board.h" 32#include "board.h"
33#include "clock.h" 33#include "clock.h"
34#include "fuse.h" 34#include "fuse.h"
35#include "pmc.h"
36
37/*
38 * Storage for debug-macro.S's state.
39 *
40 * This must be in .data not .bss so that it gets initialized each time the
41 * kernel is loaded. The data is declared here rather than debug-macro.S so
42 * that multiple inclusions of debug-macro.S point at the same data.
43 */
44#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF)
45u32 tegra_uart_config[3] = {
46 /* Debug UART initialization required */
47 1,
48 /* Debug UART physical address */
49 (u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET),
50 /* Debug UART virtual address */
51 (u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET),
52};
35 53
36#ifdef CONFIG_OF 54#ifdef CONFIG_OF
37static const struct of_device_id tegra_dt_irq_match[] __initconst = { 55static const struct of_device_id tegra_dt_irq_match[] __initconst = {
@@ -100,6 +118,7 @@ void __init tegra20_init_early(void)
100 tegra2_init_clocks(); 118 tegra2_init_clocks();
101 tegra_clk_init_from_table(tegra20_clk_init_table); 119 tegra_clk_init_from_table(tegra20_clk_init_table);
102 tegra_init_cache(0x331, 0x441); 120 tegra_init_cache(0x331, 0x441);
121 tegra_pmc_init();
103} 122}
104#endif 123#endif
105#ifdef CONFIG_ARCH_TEGRA_3x_SOC 124#ifdef CONFIG_ARCH_TEGRA_3x_SOC
@@ -107,5 +126,6 @@ void __init tegra30_init_early(void)
107{ 126{
108 tegra30_init_clocks(); 127 tegra30_init_clocks();
109 tegra_init_cache(0x441, 0x551); 128 tegra_init_cache(0x441, 0x551);
129 tegra_pmc_init();
110} 130}
111#endif 131#endif
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index c0cf967e47d3..abea4f6e2dd5 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -33,6 +33,8 @@
33#include <mach/iomap.h> 33#include <mach/iomap.h>
34#include <mach/suspend.h> 34#include <mach/suspend.h>
35 35
36#include "apbio.h"
37
36#define APB_DMA_GEN 0x000 38#define APB_DMA_GEN 0x000
37#define GEN_ENABLE (1<<31) 39#define GEN_ENABLE (1<<31)
38 40
@@ -50,8 +52,6 @@
50#define CSR_ONCE (1<<27) 52#define CSR_ONCE (1<<27)
51#define CSR_FLOW (1<<21) 53#define CSR_FLOW (1<<21)
52#define CSR_REQ_SEL_SHIFT 16 54#define CSR_REQ_SEL_SHIFT 16
53#define CSR_REQ_SEL_MASK (0x1F<<CSR_REQ_SEL_SHIFT)
54#define CSR_REQ_SEL_INVALID (31<<CSR_REQ_SEL_SHIFT)
55#define CSR_WCOUNT_SHIFT 2 55#define CSR_WCOUNT_SHIFT 2
56#define CSR_WCOUNT_MASK 0xFFFC 56#define CSR_WCOUNT_MASK 0xFFFC
57 57
@@ -133,6 +133,7 @@ struct tegra_dma_channel {
133 133
134static bool tegra_dma_initialized; 134static bool tegra_dma_initialized;
135static DEFINE_MUTEX(tegra_dma_lock); 135static DEFINE_MUTEX(tegra_dma_lock);
136static DEFINE_SPINLOCK(enable_lock);
136 137
137static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS); 138static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
138static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS]; 139static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
@@ -180,36 +181,94 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch)
180 181
181static int tegra_dma_cancel(struct tegra_dma_channel *ch) 182static int tegra_dma_cancel(struct tegra_dma_channel *ch)
182{ 183{
183 u32 csr;
184 unsigned long irq_flags; 184 unsigned long irq_flags;
185 185
186 spin_lock_irqsave(&ch->lock, irq_flags); 186 spin_lock_irqsave(&ch->lock, irq_flags);
187 while (!list_empty(&ch->list)) 187 while (!list_empty(&ch->list))
188 list_del(ch->list.next); 188 list_del(ch->list.next);
189 189
190 csr = readl(ch->addr + APB_DMA_CHAN_CSR);
191 csr &= ~CSR_REQ_SEL_MASK;
192 csr |= CSR_REQ_SEL_INVALID;
193 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
194
195 tegra_dma_stop(ch); 190 tegra_dma_stop(ch);
196 191
197 spin_unlock_irqrestore(&ch->lock, irq_flags); 192 spin_unlock_irqrestore(&ch->lock, irq_flags);
198 return 0; 193 return 0;
199} 194}
200 195
196static unsigned int get_channel_status(struct tegra_dma_channel *ch,
197 struct tegra_dma_req *req, bool is_stop_dma)
198{
199 void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
200 unsigned int status;
201
202 if (is_stop_dma) {
203 /*
204 * STOP the DMA and get the transfer count.
205 * Getting the transfer count is tricky.
206 * - Globally disable DMA on all channels
207 * - Read the channel's status register to know the number
208 * of pending bytes to be transfered.
209 * - Stop the dma channel
210 * - Globally re-enable DMA to resume other transfers
211 */
212 spin_lock(&enable_lock);
213 writel(0, addr + APB_DMA_GEN);
214 udelay(20);
215 status = readl(ch->addr + APB_DMA_CHAN_STA);
216 tegra_dma_stop(ch);
217 writel(GEN_ENABLE, addr + APB_DMA_GEN);
218 spin_unlock(&enable_lock);
219 if (status & STA_ISE_EOC) {
220 pr_err("Got Dma Int here clearing");
221 writel(status, ch->addr + APB_DMA_CHAN_STA);
222 }
223 req->status = TEGRA_DMA_REQ_ERROR_ABORTED;
224 } else {
225 status = readl(ch->addr + APB_DMA_CHAN_STA);
226 }
227 return status;
228}
229
230/* should be called with the channel lock held */
231static unsigned int dma_active_count(struct tegra_dma_channel *ch,
232 struct tegra_dma_req *req, unsigned int status)
233{
234 unsigned int to_transfer;
235 unsigned int req_transfer_count;
236 unsigned int bytes_transferred;
237
238 to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1;
239 req_transfer_count = ch->req_transfer_count + 1;
240 bytes_transferred = req_transfer_count;
241 if (status & STA_BUSY)
242 bytes_transferred -= to_transfer;
243 /*
244 * In continuous transfer mode, DMA only tracks the count of the
245 * half DMA buffer. So, if the DMA already finished half the DMA
246 * then add the half buffer to the completed count.
247 */
248 if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) {
249 if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
250 bytes_transferred += req_transfer_count;
251 if (status & STA_ISE_EOC)
252 bytes_transferred += req_transfer_count;
253 }
254 bytes_transferred *= 4;
255 return bytes_transferred;
256}
257
201int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, 258int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
202 struct tegra_dma_req *_req) 259 struct tegra_dma_req *_req)
203{ 260{
204 unsigned int csr;
205 unsigned int status; 261 unsigned int status;
206 struct tegra_dma_req *req = NULL; 262 struct tegra_dma_req *req = NULL;
207 int found = 0; 263 int found = 0;
208 unsigned long irq_flags; 264 unsigned long irq_flags;
209 int to_transfer; 265 int stop = 0;
210 int req_transfer_count;
211 266
212 spin_lock_irqsave(&ch->lock, irq_flags); 267 spin_lock_irqsave(&ch->lock, irq_flags);
268
269 if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req)
270 stop = 1;
271
213 list_for_each_entry(req, &ch->list, node) { 272 list_for_each_entry(req, &ch->list, node) {
214 if (req == _req) { 273 if (req == _req) {
215 list_del(&req->node); 274 list_del(&req->node);
@@ -222,47 +281,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
222 return 0; 281 return 0;
223 } 282 }
224 283
225 /* STOP the DMA and get the transfer count. 284 if (!stop)
226 * Getting the transfer count is tricky. 285 goto skip_stop_dma;
227 * - Change the source selector to invalid to stop the DMA from
228 * FIFO to memory.
229 * - Read the status register to know the number of pending
230 * bytes to be transferred.
231 * - Finally stop or program the DMA to the next buffer in the
232 * list.
233 */
234 csr = readl(ch->addr + APB_DMA_CHAN_CSR);
235 csr &= ~CSR_REQ_SEL_MASK;
236 csr |= CSR_REQ_SEL_INVALID;
237 writel(csr, ch->addr + APB_DMA_CHAN_CSR);
238
239 /* Get the transfer count */
240 status = readl(ch->addr + APB_DMA_CHAN_STA);
241 to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
242 req_transfer_count = ch->req_transfer_count;
243 req_transfer_count += 1;
244 to_transfer += 1;
245
246 req->bytes_transferred = req_transfer_count;
247
248 if (status & STA_BUSY)
249 req->bytes_transferred -= to_transfer;
250
251 /* In continuous transfer mode, DMA only tracks the count of the
252 * half DMA buffer. So, if the DMA already finished half the DMA
253 * then add the half buffer to the completed count.
254 *
255 * FIXME: There can be a race here. What if the req to
256 * dequue happens at the same time as the DMA just moved to
257 * the new buffer and SW didn't yet received the interrupt?
258 */
259 if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
260 if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
261 req->bytes_transferred += req_transfer_count;
262 286
263 req->bytes_transferred *= 4; 287 status = get_channel_status(ch, req, true);
288 req->bytes_transferred = dma_active_count(ch, req, status);
264 289
265 tegra_dma_stop(ch);
266 if (!list_empty(&ch->list)) { 290 if (!list_empty(&ch->list)) {
267 /* if the list is not empty, queue the next request */ 291 /* if the list is not empty, queue the next request */
268 struct tegra_dma_req *next_req; 292 struct tegra_dma_req *next_req;
@@ -270,6 +294,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
270 typeof(*next_req), node); 294 typeof(*next_req), node);
271 tegra_dma_update_hw(ch, next_req); 295 tegra_dma_update_hw(ch, next_req);
272 } 296 }
297
298skip_stop_dma:
273 req->status = -TEGRA_DMA_REQ_ERROR_ABORTED; 299 req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
274 300
275 spin_unlock_irqrestore(&ch->lock, irq_flags); 301 spin_unlock_irqrestore(&ch->lock, irq_flags);
@@ -357,7 +383,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
357 int channel; 383 int channel;
358 struct tegra_dma_channel *ch = NULL; 384 struct tegra_dma_channel *ch = NULL;
359 385
360 if (WARN_ON(!tegra_dma_initialized)) 386 if (!tegra_dma_initialized)
361 return NULL; 387 return NULL;
362 388
363 mutex_lock(&tegra_dma_lock); 389 mutex_lock(&tegra_dma_lock);
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 1fa26d9a1a68..17fdd4086e6f 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -23,20 +23,70 @@
23#include <mach/iomap.h> 23#include <mach/iomap.h>
24 24
25#include "fuse.h" 25#include "fuse.h"
26#include "apbio.h"
26 27
27#define FUSE_UID_LOW 0x108 28#define FUSE_UID_LOW 0x108
28#define FUSE_UID_HIGH 0x10c 29#define FUSE_UID_HIGH 0x10c
29#define FUSE_SKU_INFO 0x110 30#define FUSE_SKU_INFO 0x110
30#define FUSE_SPARE_BIT 0x200 31#define FUSE_SPARE_BIT 0x200
31 32
32static inline u32 fuse_readl(unsigned long offset) 33int tegra_sku_id;
34int tegra_cpu_process_id;
35int tegra_core_process_id;
36enum tegra_revision tegra_revision;
37
38/* The BCT to use at boot is specified by board straps that can be read
39 * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
40 */
41int tegra_bct_strapping;
42
43#define STRAP_OPT 0x008
44#define GMI_AD0 (1 << 4)
45#define GMI_AD1 (1 << 5)
46#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
47#define RAM_CODE_SHIFT 4
48
49static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
50 [TEGRA_REVISION_UNKNOWN] = "unknown",
51 [TEGRA_REVISION_A01] = "A01",
52 [TEGRA_REVISION_A02] = "A02",
53 [TEGRA_REVISION_A03] = "A03",
54 [TEGRA_REVISION_A03p] = "A03 prime",
55 [TEGRA_REVISION_A04] = "A04",
56};
57
58static inline u32 tegra_fuse_readl(unsigned long offset)
59{
60 return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
61}
62
63static inline bool get_spare_fuse(int bit)
33{ 64{
34 return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); 65 return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
35} 66}
36 67
37static inline void fuse_writel(u32 value, unsigned long offset) 68static enum tegra_revision tegra_get_revision(void)
38{ 69{
39 writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); 70 void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
71 u32 id = readl(chip_id);
72 u32 minor_rev = (id >> 16) & 0xf;
73 u32 chipid = (id >> 8) & 0xff;
74
75 switch (minor_rev) {
76 case 1:
77 return TEGRA_REVISION_A01;
78 case 2:
79 return TEGRA_REVISION_A02;
80 case 3:
81 if (chipid == 0x20 && (get_spare_fuse(18) || get_spare_fuse(19)))
82 return TEGRA_REVISION_A03p;
83 else
84 return TEGRA_REVISION_A03;
85 case 4:
86 return TEGRA_REVISION_A04;
87 default:
88 return TEGRA_REVISION_UNKNOWN;
89 }
40} 90}
41 91
42void tegra_init_fuse(void) 92void tegra_init_fuse(void)
@@ -45,40 +95,31 @@ void tegra_init_fuse(void)
45 reg |= 1 << 28; 95 reg |= 1 << 28;
46 writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); 96 writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
47 97
48 pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", 98 reg = tegra_fuse_readl(FUSE_SKU_INFO);
49 tegra_sku_id(), tegra_cpu_process_id(), 99 tegra_sku_id = reg & 0xFF;
50 tegra_core_process_id());
51}
52 100
53unsigned long long tegra_chip_uid(void) 101 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
54{ 102 tegra_cpu_process_id = (reg >> 6) & 3;
55 unsigned long long lo, hi;
56 103
57 lo = fuse_readl(FUSE_UID_LOW); 104 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
58 hi = fuse_readl(FUSE_UID_HIGH); 105 tegra_core_process_id = (reg >> 12) & 3;
59 return (hi << 32ull) | lo;
60}
61 106
62int tegra_sku_id(void) 107 reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
63{ 108 tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
64 int sku_id;
65 u32 reg = fuse_readl(FUSE_SKU_INFO);
66 sku_id = reg & 0xFF;
67 return sku_id;
68}
69 109
70int tegra_cpu_process_id(void) 110 tegra_revision = tegra_get_revision();
71{ 111
72 int cpu_process_id; 112 pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
73 u32 reg = fuse_readl(FUSE_SPARE_BIT); 113 tegra_revision_name[tegra_get_revision()],
74 cpu_process_id = (reg >> 6) & 3; 114 tegra_sku_id, tegra_cpu_process_id,
75 return cpu_process_id; 115 tegra_core_process_id);
76} 116}
77 117
78int tegra_core_process_id(void) 118unsigned long long tegra_chip_uid(void)
79{ 119{
80 int core_process_id; 120 unsigned long long lo, hi;
81 u32 reg = fuse_readl(FUSE_SPARE_BIT); 121
82 core_process_id = (reg >> 12) & 3; 122 lo = tegra_fuse_readl(FUSE_UID_LOW);
83 return core_process_id; 123 hi = tegra_fuse_readl(FUSE_UID_HIGH);
124 return (hi << 32ull) | lo;
84} 125}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index 584b2e27dbda..d65d2abf803b 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -1,6 +1,4 @@
1/* 1/*
2 * arch/arm/mach-tegra/fuse.c
3 *
4 * Copyright (C) 2010 Google, Inc. 2 * Copyright (C) 2010 Google, Inc.
5 * 3 *
6 * Author: 4 * Author:
@@ -17,8 +15,34 @@
17 * 15 *
18 */ 16 */
19 17
18#ifndef __MACH_TEGRA_FUSE_H
19#define __MACH_TEGRA_FUSE_H
20
21enum tegra_revision {
22 TEGRA_REVISION_UNKNOWN = 0,
23 TEGRA_REVISION_A01,
24 TEGRA_REVISION_A02,
25 TEGRA_REVISION_A03,
26 TEGRA_REVISION_A03p,
27 TEGRA_REVISION_A04,
28 TEGRA_REVISION_MAX,
29};
30
31#define SKU_ID_T20 8
32#define SKU_ID_T25SE 20
33#define SKU_ID_AP25 23
34#define SKU_ID_T25 24
35#define SKU_ID_AP25E 27
36#define SKU_ID_T25E 28
37
38extern int tegra_sku_id;
39extern int tegra_cpu_process_id;
40extern int tegra_core_process_id;
41extern enum tegra_revision tegra_revision;
42
43extern int tegra_bct_strapping;
44
20unsigned long long tegra_chip_uid(void); 45unsigned long long tegra_chip_uid(void);
21int tegra_sku_id(void);
22int tegra_cpu_process_id(void);
23int tegra_core_process_id(void);
24void tegra_init_fuse(void); 46void tegra_init_fuse(void);
47
48#endif
diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S
index 619abc63aee8..90069abd37bd 100644
--- a/arch/arm/mach-tegra/include/mach/debug-macro.S
+++ b/arch/arm/mach-tegra/include/mach/debug-macro.S
@@ -1,11 +1,17 @@
1/* 1/*
2 * arch/arm/mach-tegra/include/mach/debug-macro.S 2 * arch/arm/mach-tegra/include/mach/debug-macro.S
3 * 3 *
4 * Copyright (C) 2010 Google, Inc. 4 * Copyright (C) 2010,2011 Google, Inc.
5 * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
5 * 6 *
6 * Author: 7 * Author:
7 * Colin Cross <ccross@google.com> 8 * Colin Cross <ccross@google.com>
8 * Erik Gilling <konkers@google.com> 9 * Erik Gilling <konkers@google.com>
10 * Doug Anderson <dianders@chromium.org>
11 * Stephen Warren <swarren@nvidia.com>
12 *
13 * Portions based on mach-omap2's debug-macro.S
14 * Copyright (C) 1994-1999 Russell King
9 * 15 *
10 * This software is licensed under the terms of the GNU General Public 16 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and 17 * License version 2, as published by the Free Software Foundation, and
@@ -18,18 +24,78 @@
18 * 24 *
19 */ 25 */
20 26
27#include <linux/serial_reg.h>
28
21#include <mach/io.h> 29#include <mach/io.h>
22#include <mach/iomap.h> 30#include <mach/iomap.h>
31#include <mach/irammap.h>
32
33 .macro addruart, rp, rv, tmp
34 adr \rp, 99f @ actual addr of 99f
35 ldr \rv, [\rp] @ linked addr is stored there
36 sub \rv, \rv, \rp @ offset between the two
37 ldr \rp, [\rp, #4] @ linked tegra_uart_config
38 sub \tmp, \rp, \rv @ actual tegra_uart_config
39 ldr \rp, [\tmp] @ Load tegra_uart_config
40 cmp \rp, #1 @ needs intitialization?
41 bne 100f @ no; go load the addresses
42 mov \rv, #0 @ yes; record init is done
43 str \rv, [\tmp]
44 mov \rp, #TEGRA_IRAM_BASE @ See if cookie is in IRAM
45 ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET]
46 movw \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff
47 movt \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16
48 cmp \rv, \rp @ Cookie present?
49 bne 100f @ No, use default UART
50 mov \rp, #TEGRA_IRAM_BASE @ Load UART address from IRAM
51 ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4]
52 str \rv, [\tmp, #4] @ Store in tegra_uart_phys
53 sub \rv, \rv, #IO_APB_PHYS @ Calculate virt address
54 add \rv, \rv, #IO_APB_VIRT
55 str \rv, [\tmp, #8] @ Store in tegra_uart_virt
56 b 100f
57
58 .align
5999: .word .
60 .word tegra_uart_config
61 .ltorg
62
63100: ldr \rp, [\tmp, #4] @ Load tegra_uart_phys
64 ldr \rv, [\tmp, #8] @ Load tegra_uart_virt
65 .endm
66
67#define UART_SHIFT 2
68
69/*
70 * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra
71 * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case.
72 * We use the fact that all 5 valid UART addresses all have something in the
73 * 2nd-to-lowest byte.
74 */
23 75
24 .macro addruart, rp, rv, tmp 76 .macro senduart, rd, rx
25 ldr \rp, =IO_APB_PHYS @ physical 77 tst \rx, #0x0000ff00
26 ldr \rv, =IO_APB_VIRT @ virtual 78 strneb \rd, [\rx, #UART_TX << UART_SHIFT]
27 orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF) 791001:
28 orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00) 80 .endm
29 orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF)
30 orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
31 .endm
32 81
33#define UART_SHIFT 2 82 .macro busyuart, rd, rx
34#include <asm/hardware/debug-8250.S> 83 tst \rx, #0x0000ff00
84 beq 1002f
851001: ldrb \rd, [\rx, #UART_LSR << UART_SHIFT]
86 and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
87 teq \rd, #UART_LSR_TEMT | UART_LSR_THRE
88 bne 1001b
891002:
90 .endm
35 91
92 .macro waituart, rd, rx
93#ifdef FLOW_CONTROL
94 tst \rx, #0x0000ff00
95 beq 1002f
961001: ldrb \rd, [\rx, #UART_MSR << UART_SHIFT]
97 tst \rd, #UART_MSR_CTS
98 beq 1001b
991002:
100#endif
101 .endm
diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
index 87d37fdf5084..6140820555e1 100644
--- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h
+++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
@@ -25,8 +25,6 @@
25 25
26#define TEGRA_NR_GPIOS INT_GPIO_NR 26#define TEGRA_NR_GPIOS INT_GPIO_NR
27 27
28#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio))
29
30struct tegra_gpio_table { 28struct tegra_gpio_table {
31 int gpio; /* GPIO number */ 29 int gpio; /* GPIO number */
32 bool enable; /* Enable for GPIO at init? */ 30 bool enable; /* Enable for GPIO at init? */
diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h
new file mode 100644
index 000000000000..0cbe63261854
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/irammap.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __MACH_TEGRA_IRAMMAP_H
18#define __MACH_TEGRA_IRAMMAP_H
19
20#include <asm/sizes.h>
21
22/* The first 1K of IRAM is permanently reserved for the CPU reset handler */
23#define TEGRA_IRAM_RESET_HANDLER_OFFSET 0
24#define TEGRA_IRAM_RESET_HANDLER_SIZE SZ_1K
25
26/*
27 * These locations are written to by uncompress.h, and read by debug-macro.S.
28 * The first word holds the cookie value if the data is valid. The second
29 * word holds the UART physical address.
30 */
31#define TEGRA_IRAM_DEBUG_UART_OFFSET SZ_1K
32#define TEGRA_IRAM_DEBUG_UART_SIZE 8
33#define TEGRA_IRAM_DEBUG_UART_COOKIE 0x55415254
34
35#endif
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
index 4e8323770c79..b066ba0ee3c3 100644
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -2,10 +2,14 @@
2 * arch/arm/mach-tegra/include/mach/uncompress.h 2 * arch/arm/mach-tegra/include/mach/uncompress.h
3 * 3 *
4 * Copyright (C) 2010 Google, Inc. 4 * Copyright (C) 2010 Google, Inc.
5 * Copyright (C) 2011 Google, Inc.
6 * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
5 * 7 *
6 * Author: 8 * Author:
7 * Colin Cross <ccross@google.com> 9 * Colin Cross <ccross@google.com>
8 * Erik Gilling <konkers@google.com> 10 * Erik Gilling <konkers@google.com>
11 * Doug Anderson <dianders@chromium.org>
12 * Stephen Warren <swarren@nvidia.com>
9 * 13 *
10 * This software is licensed under the terms of the GNU General Public 14 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and 15 * License version 2, as published by the Free Software Foundation, and
@@ -21,40 +25,132 @@
21#ifndef __MACH_TEGRA_UNCOMPRESS_H 25#ifndef __MACH_TEGRA_UNCOMPRESS_H
22#define __MACH_TEGRA_UNCOMPRESS_H 26#define __MACH_TEGRA_UNCOMPRESS_H
23 27
28#include <linux/kernel.h>
24#include <linux/types.h> 29#include <linux/types.h>
25#include <linux/serial_reg.h> 30#include <linux/serial_reg.h>
26 31
27#include <mach/iomap.h> 32#include <mach/iomap.h>
33#include <mach/irammap.h>
34
35#define DEBUG_UART_SHIFT 2
36
37volatile u8 *uart;
28 38
29static void putc(int c) 39static void putc(int c)
30{ 40{
31 volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
32 int shift = 2;
33
34 if (uart == NULL) 41 if (uart == NULL)
35 return; 42 return;
36 43
37 while (!(uart[UART_LSR << shift] & UART_LSR_THRE)) 44 while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
38 barrier(); 45 barrier();
39 uart[UART_TX << shift] = c; 46 uart[UART_TX << DEBUG_UART_SHIFT] = c;
40} 47}
41 48
42static inline void flush(void) 49static inline void flush(void)
43{ 50{
44} 51}
45 52
53static inline void save_uart_address(void)
54{
55 u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);
56
57 if (uart) {
58 buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
59 buf[1] = (u32)uart;
60 } else
61 buf[0] = 0;
62}
63
64/*
65 * Setup before decompression. This is where we do UART selection for
66 * earlyprintk and init the uart_base register.
67 */
46static inline void arch_decomp_setup(void) 68static inline void arch_decomp_setup(void)
47{ 69{
48 volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; 70 static const struct {
49 int shift = 2; 71 u32 base;
72 u32 reset_reg;
73 u32 clock_reg;
74 u32 bit;
75 } uarts[] = {
76 {
77 TEGRA_UARTA_BASE,
78 TEGRA_CLK_RESET_BASE + 0x04,
79 TEGRA_CLK_RESET_BASE + 0x10,
80 6,
81 },
82 {
83 TEGRA_UARTB_BASE,
84 TEGRA_CLK_RESET_BASE + 0x04,
85 TEGRA_CLK_RESET_BASE + 0x10,
86 7,
87 },
88 {
89 TEGRA_UARTC_BASE,
90 TEGRA_CLK_RESET_BASE + 0x08,
91 TEGRA_CLK_RESET_BASE + 0x14,
92 23,
93 },
94 {
95 TEGRA_UARTD_BASE,
96 TEGRA_CLK_RESET_BASE + 0x0c,
97 TEGRA_CLK_RESET_BASE + 0x18,
98 1,
99 },
100 {
101 TEGRA_UARTE_BASE,
102 TEGRA_CLK_RESET_BASE + 0x0c,
103 TEGRA_CLK_RESET_BASE + 0x18,
104 2,
105 },
106 };
107 int i;
108 volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
109 u32 chip, div;
110
111 /*
112 * Look for the first UART that:
113 * a) Is not in reset.
114 * b) Is clocked.
115 * c) Has a 'D' in the scratchpad register.
116 *
117 * Note that on Tegra30, the first two conditions are required, since
118 * if not true, accesses to the UART scratch register will hang.
119 * Tegra20 doesn't have this issue.
120 *
121 * The intent is that the bootloader will tell the kernel which UART
122 * to use by setting up those conditions. If nothing found, we'll fall
123 * back to what's specified in TEGRA_DEBUG_UART_BASE.
124 */
125 for (i = 0; i < ARRAY_SIZE(uarts); i++) {
126 if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
127 continue;
50 128
129 if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
130 continue;
131
132 uart = (volatile u8 *)uarts[i].base;
133 if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
134 continue;
135
136 break;
137 }
138 if (i == ARRAY_SIZE(uarts))
139 uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
140 save_uart_address();
51 if (uart == NULL) 141 if (uart == NULL)
52 return; 142 return;
53 143
54 uart[UART_LCR << shift] |= UART_LCR_DLAB; 144 chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
55 uart[UART_DLL << shift] = 0x75; 145 if (chip == 0x20)
56 uart[UART_DLM << shift] = 0x0; 146 div = 0x0075;
57 uart[UART_LCR << shift] = 3; 147 else
148 div = 0x00dd;
149
150 uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
151 uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
152 uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
153 uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
58} 154}
59 155
60static inline void arch_decomp_wdog(void) 156static inline void arch_decomp_wdog(void)
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
new file mode 100644
index 000000000000..7af6a54404be
--- /dev/null
+++ b/arch/arm/mach-tegra/pmc.c
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <linux/kernel.h>
19#include <linux/io.h>
20#include <linux/of.h>
21
22#include <mach/iomap.h>
23
24#define PMC_CTRL 0x0
25#define PMC_CTRL_INTR_LOW (1 << 17)
26
27static inline u32 tegra_pmc_readl(u32 reg)
28{
29 return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
30}
31
32static inline void tegra_pmc_writel(u32 val, u32 reg)
33{
34 writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
35}
36
37#ifdef CONFIG_OF
38static const struct of_device_id matches[] __initconst = {
39 { .compatible = "nvidia,tegra20-pmc" },
40 { }
41};
42#endif
43
44void __init tegra_pmc_init(void)
45{
46 /*
47 * For now, Harmony is the only board that uses the PMC, and it wants
48 * the signal inverted. Seaboard would too if it used the PMC.
49 * Hopefully by the time other boards want to use the PMC, everything
50 * will be device-tree, or they also want it inverted.
51 */
52 bool invert_interrupt = true;
53 u32 val;
54
55#ifdef CONFIG_OF
56 if (of_have_populated_dt()) {
57 struct device_node *np;
58
59 invert_interrupt = false;
60
61 np = of_find_matching_node(NULL, matches);
62 if (np) {
63 if (of_find_property(np, "nvidia,invert-interrupt",
64 NULL))
65 invert_interrupt = true;
66 }
67 }
68#endif
69
70 val = tegra_pmc_readl(PMC_CTRL);
71 if (invert_interrupt)
72 val |= PMC_CTRL_INTR_LOW;
73 else
74 val &= ~PMC_CTRL_INTR_LOW;
75 tegra_pmc_writel(val, PMC_CTRL);
76}
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
new file mode 100644
index 000000000000..8995ee4a8768
--- /dev/null
+++ b/arch/arm/mach-tegra/pmc.h
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#ifndef __MACH_TEGRA_PMC_H
19#define __MACH_TEGRA_PMC_H
20
21void tegra_pmc_init(void);
22
23#endif
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 1976e934cdd9..592a4eeb5328 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c)
720{ 720{
721 tegra2_pll_clk_init(c); 721 tegra2_pll_clk_init(c);
722 722
723 if (tegra_sku_id() == 7) 723 if (tegra_sku_id == 7)
724 c->max_rate = 750000000; 724 c->max_rate = 750000000;
725} 725}
726 726
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
index 0f7ae6e90b55..5070d833bdd1 100644
--- a/arch/arm/mach-tegra/tegra2_emc.c
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -16,14 +16,19 @@
16 */ 16 */
17 17
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/device.h>
19#include <linux/clk.h> 20#include <linux/clk.h>
20#include <linux/err.h> 21#include <linux/err.h>
21#include <linux/io.h> 22#include <linux/io.h>
22#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/platform_device.h>
26#include <linux/platform_data/tegra_emc.h>
23 27
24#include <mach/iomap.h> 28#include <mach/iomap.h>
25 29
26#include "tegra2_emc.h" 30#include "tegra2_emc.h"
31#include "fuse.h"
27 32
28#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE 33#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
29static bool emc_enable = true; 34static bool emc_enable = true;
@@ -32,18 +37,17 @@ static bool emc_enable;
32#endif 37#endif
33module_param(emc_enable, bool, 0644); 38module_param(emc_enable, bool, 0644);
34 39
35static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); 40static struct platform_device *emc_pdev;
36static const struct tegra_emc_table *tegra_emc_table; 41static void __iomem *emc_regbase;
37static int tegra_emc_table_size;
38 42
39static inline void emc_writel(u32 val, unsigned long addr) 43static inline void emc_writel(u32 val, unsigned long addr)
40{ 44{
41 writel(val, emc + addr); 45 writel(val, emc_regbase + addr);
42} 46}
43 47
44static inline u32 emc_readl(unsigned long addr) 48static inline u32 emc_readl(unsigned long addr)
45{ 49{
46 return readl(emc + addr); 50 return readl(emc_regbase + addr);
47} 51}
48 52
49static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { 53static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
@@ -98,15 +102,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
98/* Select the closest EMC rate that is higher than the requested rate */ 102/* Select the closest EMC rate that is higher than the requested rate */
99long tegra_emc_round_rate(unsigned long rate) 103long tegra_emc_round_rate(unsigned long rate)
100{ 104{
105 struct tegra_emc_pdata *pdata;
101 int i; 106 int i;
102 int best = -1; 107 int best = -1;
103 unsigned long distance = ULONG_MAX; 108 unsigned long distance = ULONG_MAX;
104 109
105 if (!tegra_emc_table) 110 if (!emc_pdev)
106 return -EINVAL; 111 return -EINVAL;
107 112
108 if (!emc_enable) 113 pdata = emc_pdev->dev.platform_data;
109 return -EINVAL;
110 114
111 pr_debug("%s: %lu\n", __func__, rate); 115 pr_debug("%s: %lu\n", __func__, rate);
112 116
@@ -116,10 +120,10 @@ long tegra_emc_round_rate(unsigned long rate)
116 */ 120 */
117 rate = rate / 2 / 1000; 121 rate = rate / 2 / 1000;
118 122
119 for (i = 0; i < tegra_emc_table_size; i++) { 123 for (i = 0; i < pdata->num_tables; i++) {
120 if (tegra_emc_table[i].rate >= rate && 124 if (pdata->tables[i].rate >= rate &&
121 (tegra_emc_table[i].rate - rate) < distance) { 125 (pdata->tables[i].rate - rate) < distance) {
122 distance = tegra_emc_table[i].rate - rate; 126 distance = pdata->tables[i].rate - rate;
123 best = i; 127 best = i;
124 } 128 }
125 } 129 }
@@ -127,9 +131,9 @@ long tegra_emc_round_rate(unsigned long rate)
127 if (best < 0) 131 if (best < 0)
128 return -EINVAL; 132 return -EINVAL;
129 133
130 pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate); 134 pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate);
131 135
132 return tegra_emc_table[best].rate * 2 * 1000; 136 return pdata->tables[best].rate * 2 * 1000;
133} 137}
134 138
135/* 139/*
@@ -142,37 +146,211 @@ long tegra_emc_round_rate(unsigned long rate)
142 */ 146 */
143int tegra_emc_set_rate(unsigned long rate) 147int tegra_emc_set_rate(unsigned long rate)
144{ 148{
149 struct tegra_emc_pdata *pdata;
145 int i; 150 int i;
146 int j; 151 int j;
147 152
148 if (!tegra_emc_table) 153 if (!emc_pdev)
149 return -EINVAL; 154 return -EINVAL;
150 155
156 pdata = emc_pdev->dev.platform_data;
157
151 /* 158 /*
152 * The EMC clock rate is twice the bus rate, and the bus rate is 159 * The EMC clock rate is twice the bus rate, and the bus rate is
153 * measured in kHz 160 * measured in kHz
154 */ 161 */
155 rate = rate / 2 / 1000; 162 rate = rate / 2 / 1000;
156 163
157 for (i = 0; i < tegra_emc_table_size; i++) 164 for (i = 0; i < pdata->num_tables; i++)
158 if (tegra_emc_table[i].rate == rate) 165 if (pdata->tables[i].rate == rate)
159 break; 166 break;
160 167
161 if (i >= tegra_emc_table_size) 168 if (i >= pdata->num_tables)
162 return -EINVAL; 169 return -EINVAL;
163 170
164 pr_debug("%s: setting to %lu\n", __func__, rate); 171 pr_debug("%s: setting to %lu\n", __func__, rate);
165 172
166 for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) 173 for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
167 emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]); 174 emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]);
168 175
169 emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]); 176 emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]);
170 177
171 return 0; 178 return 0;
172} 179}
173 180
174void tegra_init_emc(const struct tegra_emc_table *table, int table_size) 181#ifdef CONFIG_OF
182static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
183{
184 struct device_node *iter;
185 u32 reg;
186
187 for_each_child_of_node(np, iter) {
188 if (of_property_read_u32(np, "nvidia,ram-code", &reg))
189 continue;
190 if (reg == tegra_bct_strapping)
191 return of_node_get(iter);
192 }
193
194 return NULL;
195}
196
197static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
198 struct platform_device *pdev)
199{
200 struct device_node *np = pdev->dev.of_node;
201 struct device_node *tnp, *iter;
202 struct tegra_emc_pdata *pdata;
203 int ret, i, num_tables;
204
205 if (!np)
206 return NULL;
207
208 if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
209 tnp = tegra_emc_ramcode_devnode(np);
210 if (!tnp)
211 dev_warn(&pdev->dev,
212 "can't find emc table for ram-code 0x%02x\n",
213 tegra_bct_strapping);
214 } else
215 tnp = of_node_get(np);
216
217 if (!tnp)
218 return NULL;
219
220 num_tables = 0;
221 for_each_child_of_node(tnp, iter)
222 if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table"))
223 num_tables++;
224
225 if (!num_tables) {
226 pdata = NULL;
227 goto out;
228 }
229
230 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
231 pdata->tables = devm_kzalloc(&pdev->dev,
232 sizeof(*pdata->tables) * num_tables,
233 GFP_KERNEL);
234
235 i = 0;
236 for_each_child_of_node(tnp, iter) {
237 u32 prop;
238
239 ret = of_property_read_u32(iter, "clock-frequency", &prop);
240 if (ret) {
241 dev_err(&pdev->dev, "no clock-frequency in %s\n",
242 iter->full_name);
243 continue;
244 }
245 pdata->tables[i].rate = prop;
246
247 ret = of_property_read_u32_array(iter, "nvidia,emc-registers",
248 pdata->tables[i].regs,
249 TEGRA_EMC_NUM_REGS);
250 if (ret) {
251 dev_err(&pdev->dev,
252 "malformed emc-registers property in %s\n",
253 iter->full_name);
254 continue;
255 }
256
257 i++;
258 }
259 pdata->num_tables = i;
260
261out:
262 of_node_put(tnp);
263 return pdata;
264}
265#else
266static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
267 struct platform_device *pdev)
268{
269 return NULL;
270}
271#endif
272
273static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev)
274{
275 struct clk *c = clk_get_sys(NULL, "emc");
276 struct tegra_emc_pdata *pdata;
277 unsigned long khz;
278 int i;
279
280 WARN_ON(pdev->dev.platform_data);
281 BUG_ON(IS_ERR_OR_NULL(c));
282
283 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
284 pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables),
285 GFP_KERNEL);
286
287 pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000;
288
289 for (i = 0; i < TEGRA_EMC_NUM_REGS; i++)
290 pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]);
291
292 pdata->num_tables = 1;
293
294 khz = pdata->tables[0].rate;
295 dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, "
296 "%ld kHz mem\n", khz * 2, khz);
297
298 return pdata;
299}
300
301static int __devinit tegra_emc_probe(struct platform_device *pdev)
302{
303 struct tegra_emc_pdata *pdata;
304 struct resource *res;
305
306 if (!emc_enable) {
307 dev_err(&pdev->dev, "disabled per module parameter\n");
308 return -ENODEV;
309 }
310
311 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
312 if (!res) {
313 dev_err(&pdev->dev, "missing register base\n");
314 return -ENOMEM;
315 }
316
317 emc_regbase = devm_request_and_ioremap(&pdev->dev, res);
318 if (!emc_regbase) {
319 dev_err(&pdev->dev, "failed to remap registers\n");
320 return -ENOMEM;
321 }
322
323 pdata = pdev->dev.platform_data;
324
325 if (!pdata)
326 pdata = tegra_emc_dt_parse_pdata(pdev);
327
328 if (!pdata)
329 pdata = tegra_emc_fill_pdata(pdev);
330
331 pdev->dev.platform_data = pdata;
332
333 emc_pdev = pdev;
334
335 return 0;
336}
337
338static struct of_device_id tegra_emc_of_match[] __devinitdata = {
339 { .compatible = "nvidia,tegra20-emc", },
340 { },
341};
342
343static struct platform_driver tegra_emc_driver = {
344 .driver = {
345 .name = "tegra-emc",
346 .owner = THIS_MODULE,
347 .of_match_table = tegra_emc_of_match,
348 },
349 .probe = tegra_emc_probe,
350};
351
352static int __init tegra_emc_init(void)
175{ 353{
176 tegra_emc_table = table; 354 return platform_driver_register(&tegra_emc_driver);
177 tegra_emc_table_size = table_size;
178} 355}
356device_initcall(tegra_emc_init);
diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h
index 19f08cb31603..f61409b54cb7 100644
--- a/arch/arm/mach-tegra/tegra2_emc.h
+++ b/arch/arm/mach-tegra/tegra2_emc.h
@@ -15,13 +15,10 @@
15 * 15 *
16 */ 16 */
17 17
18#define TEGRA_EMC_NUM_REGS 46 18#ifndef __MACH_TEGRA_TEGRA2_EMC_H_
19 19#define __MACH_TEGRA_TEGRA2_EMC_H
20struct tegra_emc_table {
21 unsigned long rate;
22 u32 regs[TEGRA_EMC_NUM_REGS];
23};
24 20
25int tegra_emc_set_rate(unsigned long rate); 21int tegra_emc_set_rate(unsigned long rate);
26long tegra_emc_round_rate(unsigned long rate); 22long tegra_emc_round_rate(unsigned long rate);
27void tegra_init_emc(const struct tegra_emc_table *table, int table_size); 23
24#endif