blob: ddd49a760fd4529d819cfda145f4b00e3d57a9b2 [file] [log] [blame]
dmitry pervushinbc19d892009-04-22 23:57:28 +01001/*
2 * Freescale STMP378X platform support
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/platform_device.h>
21#include <linux/irq.h>
dmitry pervushinc11c2212009-06-04 13:51:05 +010022#include <linux/dma-mapping.h>
dmitry pervushinbc19d892009-04-22 23:57:28 +010023
24#include <asm/dma.h>
25#include <asm/setup.h>
26#include <asm/mach-types.h>
27
28#include <asm/mach/arch.h>
29#include <asm/mach/irq.h>
30#include <asm/mach/map.h>
31#include <asm/mach/time.h>
32
33#include <mach/pins.h>
34#include <mach/pinmux.h>
35#include <mach/dma.h>
36#include <mach/hardware.h>
37#include <mach/system.h>
38#include <mach/platform.h>
39#include <mach/stmp3xxx.h>
40#include <mach/regs-icoll.h>
41#include <mach/regs-apbh.h>
42#include <mach/regs-apbx.h>
dmitry pervushinc11c2212009-06-04 13:51:05 +010043#include <mach/regs-pxp.h>
44#include <mach/regs-i2c.h>
dmitry pervushinbc19d892009-04-22 23:57:28 +010045
46#include "stmp378x.h"
47/*
48 * IRQ handling
49 */
50static void stmp378x_ack_irq(unsigned int irq)
51{
52 /* Tell ICOLL to release IRQ line */
dmitry pervushin98f420b2009-05-31 13:32:11 +010053 __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
dmitry pervushinbc19d892009-04-22 23:57:28 +010054
55 /* ACK current interrupt */
dmitry pervushin98f420b2009-05-31 13:32:11 +010056 __raw_writel(0x01 /* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 */,
57 REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
dmitry pervushinbc19d892009-04-22 23:57:28 +010058
59 /* Barrier */
dmitry pervushin98f420b2009-05-31 13:32:11 +010060 (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
dmitry pervushinbc19d892009-04-22 23:57:28 +010061}
62
63static void stmp378x_mask_irq(unsigned int irq)
64{
65 /* IRQ disable */
dmitry pervushin98f420b2009-05-31 13:32:11 +010066 stmp3xxx_clearl(BM_ICOLL_INTERRUPTn_ENABLE,
67 REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
dmitry pervushinbc19d892009-04-22 23:57:28 +010068}
69
70static void stmp378x_unmask_irq(unsigned int irq)
71{
72 /* IRQ enable */
dmitry pervushin98f420b2009-05-31 13:32:11 +010073 stmp3xxx_setl(BM_ICOLL_INTERRUPTn_ENABLE,
74 REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
dmitry pervushinbc19d892009-04-22 23:57:28 +010075}
76
77static struct irq_chip stmp378x_chip = {
78 .ack = stmp378x_ack_irq,
79 .mask = stmp378x_mask_irq,
80 .unmask = stmp378x_unmask_irq,
81};
82
83void __init stmp378x_init_irq(void)
84{
85 stmp3xxx_init_irq(&stmp378x_chip);
86}
87
88/*
89 * DMA interrupt handling
90 */
91void stmp3xxx_arch_dma_enable_interrupt(int channel)
92{
dmitry pervushin98f420b2009-05-31 13:32:11 +010093 void __iomem *c1, *c2;
dmitry pervushinbc19d892009-04-22 23:57:28 +010094
dmitry pervushin98f420b2009-05-31 13:32:11 +010095 switch (STMP3XXX_DMA_BUS(channel)) {
dmitry pervushinbc19d892009-04-22 23:57:28 +010096 case STMP3XXX_BUS_APBH:
dmitry pervushin98f420b2009-05-31 13:32:11 +010097 c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
98 c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
dmitry pervushinbc19d892009-04-22 23:57:28 +010099 break;
100
101 case STMP3XXX_BUS_APBX:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100102 c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
103 c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100104 break;
dmitry pervushin98f420b2009-05-31 13:32:11 +0100105
106 default:
107 return;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100108 }
dmitry pervushin98f420b2009-05-31 13:32:11 +0100109 stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c1);
110 stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c2);
dmitry pervushinbc19d892009-04-22 23:57:28 +0100111}
112EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
113
114void stmp3xxx_arch_dma_clear_interrupt(int channel)
115{
dmitry pervushin98f420b2009-05-31 13:32:11 +0100116 void __iomem *c1, *c2;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100117
dmitry pervushin98f420b2009-05-31 13:32:11 +0100118 switch (STMP3XXX_DMA_BUS(channel)) {
dmitry pervushinbc19d892009-04-22 23:57:28 +0100119 case STMP3XXX_BUS_APBH:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100120 c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
121 c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100122 break;
123
124 case STMP3XXX_BUS_APBX:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100125 c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
126 c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100127 break;
dmitry pervushin98f420b2009-05-31 13:32:11 +0100128
129 default:
130 return;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100131 }
dmitry pervushin98f420b2009-05-31 13:32:11 +0100132 stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c1);
133 stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c2);
dmitry pervushinbc19d892009-04-22 23:57:28 +0100134}
135EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
136
137int stmp3xxx_arch_dma_is_interrupt(int channel)
138{
dmitry pervushinbc19d892009-04-22 23:57:28 +0100139 int r = 0;
140
dmitry pervushin98f420b2009-05-31 13:32:11 +0100141 switch (STMP3XXX_DMA_BUS(channel)) {
dmitry pervushinbc19d892009-04-22 23:57:28 +0100142 case STMP3XXX_BUS_APBH:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100143 r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
144 (1 << STMP3XXX_DMA_CHANNEL(channel));
dmitry pervushinbc19d892009-04-22 23:57:28 +0100145 break;
146
147 case STMP3XXX_BUS_APBX:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100148 r = __raw_readl(REGS_APBX_BASE + HW_APBX_CTRL1) &
149 (1 << STMP3XXX_DMA_CHANNEL(channel));
dmitry pervushinbc19d892009-04-22 23:57:28 +0100150 break;
151 }
152 return r;
153}
154EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
155
156void stmp3xxx_arch_dma_reset_channel(int channel)
157{
dmitry pervushin98f420b2009-05-31 13:32:11 +0100158 unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
159 void __iomem *c0;
160 u32 mask;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100161
dmitry pervushin98f420b2009-05-31 13:32:11 +0100162 switch (STMP3XXX_DMA_BUS(channel)) {
dmitry pervushinbc19d892009-04-22 23:57:28 +0100163 case STMP3XXX_BUS_APBH:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100164 c0 = REGS_APBH_BASE + HW_APBH_CTRL0;
165 mask = chbit << BP_APBH_CTRL0_RESET_CHANNEL;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100166 break;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100167 case STMP3XXX_BUS_APBX:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100168 c0 = REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL;
169 mask = chbit << BP_APBX_CHANNEL_CTRL_RESET_CHANNEL;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100170 break;
dmitry pervushin98f420b2009-05-31 13:32:11 +0100171 default:
172 return;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100173 }
dmitry pervushin98f420b2009-05-31 13:32:11 +0100174
175 /* Reset channel and wait for it to complete */
176 stmp3xxx_setl(mask, c0);
177 while (__raw_readl(c0) & mask)
178 cpu_relax();
dmitry pervushinbc19d892009-04-22 23:57:28 +0100179}
180EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
181
182void stmp3xxx_arch_dma_freeze(int channel)
183{
dmitry pervushin98f420b2009-05-31 13:32:11 +0100184 unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
185 u32 mask = 1 << chbit;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100186
dmitry pervushin98f420b2009-05-31 13:32:11 +0100187 switch (STMP3XXX_DMA_BUS(channel)) {
dmitry pervushinbc19d892009-04-22 23:57:28 +0100188 case STMP3XXX_BUS_APBH:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100189 stmp3xxx_setl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
dmitry pervushinbc19d892009-04-22 23:57:28 +0100190 break;
191 case STMP3XXX_BUS_APBX:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100192 stmp3xxx_setl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
dmitry pervushinbc19d892009-04-22 23:57:28 +0100193 break;
194 }
195}
196EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
197
198void stmp3xxx_arch_dma_unfreeze(int channel)
199{
dmitry pervushin98f420b2009-05-31 13:32:11 +0100200 unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
201 u32 mask = 1 << chbit;
dmitry pervushinbc19d892009-04-22 23:57:28 +0100202
dmitry pervushin98f420b2009-05-31 13:32:11 +0100203 switch (STMP3XXX_DMA_BUS(channel)) {
dmitry pervushinbc19d892009-04-22 23:57:28 +0100204 case STMP3XXX_BUS_APBH:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100205 stmp3xxx_clearl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
dmitry pervushinbc19d892009-04-22 23:57:28 +0100206 break;
207 case STMP3XXX_BUS_APBX:
dmitry pervushin98f420b2009-05-31 13:32:11 +0100208 stmp3xxx_clearl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
dmitry pervushinbc19d892009-04-22 23:57:28 +0100209 break;
210 }
211}
212EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
213
214/*
215 * The registers are all very closely mapped, so we might as well map them all
216 * with a single mapping
217 *
218 * Logical Physical
219 * f0000000 80000000 On-chip registers
dmitry pervushin98f420b2009-05-31 13:32:11 +0100220 * f1000000 00000000 32k on-chip SRAM
dmitry pervushinbc19d892009-04-22 23:57:28 +0100221 */
222
223static struct map_desc stmp378x_io_desc[] __initdata = {
224 {
225 .virtual = (u32)STMP3XXX_REGS_BASE,
226 .pfn = __phys_to_pfn(STMP3XXX_REGS_PHBASE),
227 .length = STMP3XXX_REGS_SIZE,
228 .type = MT_DEVICE,
229 },
230 {
231 .virtual = (u32)STMP3XXX_OCRAM_BASE,
232 .pfn = __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
233 .length = STMP3XXX_OCRAM_SIZE,
234 .type = MT_DEVICE,
235 },
236};
237
dmitry pervushinc11c2212009-06-04 13:51:05 +0100238
239static u64 common_dmamask = DMA_BIT_MASK(32);
240
241/*
242 * devices that are present only on stmp378x, not on all 3xxx boards:
243 * PxP
244 * I2C
245 */
246static struct resource pxp_resource[] = {
247 {
248 .flags = IORESOURCE_MEM,
249 .start = REGS_PXP_PHYS,
250 .end = REGS_PXP_PHYS + REGS_PXP_SIZE,
251 }, {
252 .flags = IORESOURCE_IRQ,
253 .start = IRQ_PXP,
254 .end = IRQ_PXP,
255 },
256};
257
258struct platform_device stmp378x_pxp = {
259 .name = "stmp3xxx-pxp",
260 .id = -1,
261 .dev = {
262 .dma_mask = &common_dmamask,
263 .coherent_dma_mask = DMA_BIT_MASK(32),
264 },
265 .num_resources = ARRAY_SIZE(pxp_resource),
266 .resource = pxp_resource,
267};
268
269static struct resource i2c_resources[] = {
270 {
271 .flags = IORESOURCE_IRQ,
272 .start = IRQ_I2C_ERROR,
273 .end = IRQ_I2C_ERROR,
274 }, {
275 .flags = IORESOURCE_MEM,
276 .start = REGS_I2C_PHYS,
277 .end = REGS_I2C_PHYS + REGS_I2C_SIZE,
278 }, {
279 .flags = IORESOURCE_DMA,
280 .start = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
281 .end = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
282 },
283};
284
285struct platform_device stmp378x_i2c = {
286 .name = "i2c_stmp3xxx",
287 .id = 0,
288 .dev = {
289 .dma_mask = &common_dmamask,
290 .coherent_dma_mask = DMA_BIT_MASK(32),
291 },
292 .resource = i2c_resources,
293 .num_resources = ARRAY_SIZE(i2c_resources),
294};
295
dmitry pervushinbc19d892009-04-22 23:57:28 +0100296void __init stmp378x_map_io(void)
297{
298 iotable_init(stmp378x_io_desc, ARRAY_SIZE(stmp378x_io_desc));
299}