linux/arch/arm/mach-stmp378x/stmp378x.c
<<
>>
Prefs
   1/*
   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>
  22#include <linux/dma-mapping.h>
  23
  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>
  43#include <mach/regs-pxp.h>
  44#include <mach/regs-i2c.h>
  45
  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 */
  53        __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
  54
  55        /* ACK current interrupt */
  56        __raw_writel(0x01 /* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 */,
  57                        REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
  58
  59        /* Barrier */
  60        (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
  61}
  62
  63static void stmp378x_mask_irq(unsigned int irq)
  64{
  65        /* IRQ disable */
  66        stmp3xxx_clearl(BM_ICOLL_INTERRUPTn_ENABLE,
  67                        REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
  68}
  69
  70static void stmp378x_unmask_irq(unsigned int irq)
  71{
  72        /* IRQ enable */
  73        stmp3xxx_setl(BM_ICOLL_INTERRUPTn_ENABLE,
  74                      REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
  75}
  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{
  93        void __iomem *c1, *c2;
  94
  95        switch (STMP3XXX_DMA_BUS(channel)) {
  96        case STMP3XXX_BUS_APBH:
  97                c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
  98                c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
  99                break;
 100
 101        case STMP3XXX_BUS_APBX:
 102                c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
 103                c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
 104                break;
 105
 106        default:
 107                return;
 108        }
 109        stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c1);
 110        stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c2);
 111}
 112EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
 113
 114void stmp3xxx_arch_dma_clear_interrupt(int channel)
 115{
 116        void __iomem *c1, *c2;
 117
 118        switch (STMP3XXX_DMA_BUS(channel)) {
 119        case STMP3XXX_BUS_APBH:
 120                c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
 121                c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
 122                break;
 123
 124        case STMP3XXX_BUS_APBX:
 125                c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
 126                c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
 127                break;
 128
 129        default:
 130                return;
 131        }
 132        stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c1);
 133        stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c2);
 134}
 135EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
 136
 137int stmp3xxx_arch_dma_is_interrupt(int channel)
 138{
 139        int r = 0;
 140
 141        switch (STMP3XXX_DMA_BUS(channel)) {
 142        case STMP3XXX_BUS_APBH:
 143                r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
 144                        (1 << STMP3XXX_DMA_CHANNEL(channel));
 145                break;
 146
 147        case STMP3XXX_BUS_APBX:
 148                r = __raw_readl(REGS_APBX_BASE + HW_APBX_CTRL1) &
 149                        (1 << STMP3XXX_DMA_CHANNEL(channel));
 150                break;
 151        }
 152        return r;
 153}
 154EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
 155
 156void stmp3xxx_arch_dma_reset_channel(int channel)
 157{
 158        unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
 159        void __iomem *c0;
 160        u32 mask;
 161
 162        switch (STMP3XXX_DMA_BUS(channel)) {
 163        case STMP3XXX_BUS_APBH:
 164                c0 = REGS_APBH_BASE + HW_APBH_CTRL0;
 165                mask = chbit << BP_APBH_CTRL0_RESET_CHANNEL;
 166                break;
 167        case STMP3XXX_BUS_APBX:
 168                c0 = REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL;
 169                mask = chbit << BP_APBX_CHANNEL_CTRL_RESET_CHANNEL;
 170                break;
 171        default:
 172                return;
 173        }
 174
 175        /* Reset channel and wait for it to complete */
 176        stmp3xxx_setl(mask, c0);
 177        while (__raw_readl(c0) & mask)
 178                cpu_relax();
 179}
 180EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
 181
 182void stmp3xxx_arch_dma_freeze(int channel)
 183{
 184        unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
 185        u32 mask = 1 << chbit;
 186
 187        switch (STMP3XXX_DMA_BUS(channel)) {
 188        case STMP3XXX_BUS_APBH:
 189                stmp3xxx_setl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
 190                break;
 191        case STMP3XXX_BUS_APBX:
 192                stmp3xxx_setl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
 193                break;
 194        }
 195}
 196EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
 197
 198void stmp3xxx_arch_dma_unfreeze(int channel)
 199{
 200        unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
 201        u32 mask = 1 << chbit;
 202
 203        switch (STMP3XXX_DMA_BUS(channel)) {
 204        case STMP3XXX_BUS_APBH:
 205                stmp3xxx_clearl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
 206                break;
 207        case STMP3XXX_BUS_APBX:
 208                stmp3xxx_clearl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
 209                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
 220 * f1000000     00000000        32k on-chip SRAM
 221 */
 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
 238
 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
 296void __init stmp378x_map_io(void)
 297{
 298        iotable_init(stmp378x_io_desc, ARRAY_SIZE(stmp378x_io_desc));
 299}
 300