linux/arch/arm/mach-ixp4xx/common.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-ixp4xx/common.c
   3 *
   4 * Generic code shared across all IXP4XX platforms
   5 *
   6 * Maintainer: Deepak Saxena <dsaxena@plexity.net>
   7 *
   8 * Copyright 2002 (c) Intel Corporation
   9 * Copyright 2003-2004 (c) MontaVista, Software, Inc. 
  10 * 
  11 * This file is licensed under  the terms of the GNU General Public 
  12 * License version 2. This program is licensed "as is" without any 
  13 * warranty of any kind, whether express or implied.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/mm.h>
  18#include <linux/init.h>
  19#include <linux/serial.h>
  20#include <linux/tty.h>
  21#include <linux/platform_device.h>
  22#include <linux/serial_core.h>
  23#include <linux/interrupt.h>
  24#include <linux/bitops.h>
  25#include <linux/io.h>
  26#include <linux/export.h>
  27#include <linux/cpu.h>
  28#include <linux/pci.h>
  29#include <linux/sched_clock.h>
  30#include <linux/irqchip/irq-ixp4xx.h>
  31#include <linux/platform_data/timer-ixp4xx.h>
  32#include <linux/dma-map-ops.h>
  33#include <mach/udc.h>
  34#include <mach/hardware.h>
  35#include <mach/io.h>
  36#include <linux/uaccess.h>
  37#include <asm/page.h>
  38#include <asm/exception.h>
  39#include <asm/irq.h>
  40#include <asm/system_misc.h>
  41#include <asm/mach/map.h>
  42#include <asm/mach/irq.h>
  43#include <asm/mach/time.h>
  44
  45#include "irqs.h"
  46
  47#define IXP4XX_TIMER_FREQ 66666000
  48
  49/*************************************************************************
  50 * IXP4xx chipset I/O mapping
  51 *************************************************************************/
  52static struct map_desc ixp4xx_io_desc[] __initdata = {
  53        {       /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */
  54                .virtual        = (unsigned long)IXP4XX_PERIPHERAL_BASE_VIRT,
  55                .pfn            = __phys_to_pfn(IXP4XX_PERIPHERAL_BASE_PHYS),
  56                .length         = IXP4XX_PERIPHERAL_REGION_SIZE,
  57                .type           = MT_DEVICE
  58        }, {    /* Expansion Bus Config Registers */
  59                .virtual        = (unsigned long)IXP4XX_EXP_CFG_BASE_VIRT,
  60                .pfn            = __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS),
  61                .length         = IXP4XX_EXP_CFG_REGION_SIZE,
  62                .type           = MT_DEVICE
  63        }, {    /* PCI Registers */
  64                .virtual        = (unsigned long)IXP4XX_PCI_CFG_BASE_VIRT,
  65                .pfn            = __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS),
  66                .length         = IXP4XX_PCI_CFG_REGION_SIZE,
  67                .type           = MT_DEVICE
  68        },
  69};
  70
  71void __init ixp4xx_map_io(void)
  72{
  73        iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc));
  74}
  75
  76void __init ixp4xx_init_irq(void)
  77{
  78        /*
  79         * ixp4xx does not implement the XScale PWRMODE register
  80         * so it must not call cpu_do_idle().
  81         */
  82        cpu_idle_poll_ctrl(true);
  83
  84        ixp4xx_irq_init(IXP4XX_INTC_BASE_PHYS,
  85                        (cpu_is_ixp46x() || cpu_is_ixp43x()));
  86}
  87
  88void __init ixp4xx_timer_init(void)
  89{
  90        return ixp4xx_timer_setup(IXP4XX_TIMER_BASE_PHYS,
  91                                  IRQ_IXP4XX_TIMER1,
  92                                  IXP4XX_TIMER_FREQ);
  93}
  94
  95static struct pxa2xx_udc_mach_info ixp4xx_udc_info;
  96
  97void __init ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info)
  98{
  99        memcpy(&ixp4xx_udc_info, info, sizeof *info);
 100}
 101
 102static struct resource ixp4xx_udc_resources[] = {
 103        [0] = {
 104                .start  = 0xc800b000,
 105                .end    = 0xc800bfff,
 106                .flags  = IORESOURCE_MEM,
 107        },
 108        [1] = {
 109                .start  = IRQ_IXP4XX_USB,
 110                .end    = IRQ_IXP4XX_USB,
 111                .flags  = IORESOURCE_IRQ,
 112        },
 113};
 114
 115static struct resource ixp4xx_gpio_resource[] = {
 116        {
 117                .start = IXP4XX_GPIO_BASE_PHYS,
 118                .end = IXP4XX_GPIO_BASE_PHYS + 0xfff,
 119                .flags = IORESOURCE_MEM,
 120        },
 121};
 122
 123static struct platform_device ixp4xx_gpio_device = {
 124        .name           = "ixp4xx-gpio",
 125        .id             = -1,
 126        .dev = {
 127                .coherent_dma_mask      = DMA_BIT_MASK(32),
 128        },
 129        .resource = ixp4xx_gpio_resource,
 130        .num_resources  = ARRAY_SIZE(ixp4xx_gpio_resource),
 131};
 132
 133/*
 134 * USB device controller. The IXP4xx uses the same controller as PXA25X,
 135 * so we just use the same device.
 136 */
 137static struct platform_device ixp4xx_udc_device = {
 138        .name           = "pxa25x-udc",
 139        .id             = -1,
 140        .num_resources  = 2,
 141        .resource       = ixp4xx_udc_resources,
 142        .dev            = {
 143                .platform_data = &ixp4xx_udc_info,
 144        },
 145};
 146
 147static struct resource ixp4xx_npe_resources[] = {
 148        {
 149                .start = IXP4XX_NPEA_BASE_PHYS,
 150                .end = IXP4XX_NPEA_BASE_PHYS + 0xfff,
 151                .flags = IORESOURCE_MEM,
 152        },
 153        {
 154                .start = IXP4XX_NPEB_BASE_PHYS,
 155                .end = IXP4XX_NPEB_BASE_PHYS + 0xfff,
 156                .flags = IORESOURCE_MEM,
 157        },
 158        {
 159                .start = IXP4XX_NPEC_BASE_PHYS,
 160                .end = IXP4XX_NPEC_BASE_PHYS + 0xfff,
 161                .flags = IORESOURCE_MEM,
 162        },
 163
 164};
 165
 166static struct platform_device ixp4xx_npe_device = {
 167        .name           = "ixp4xx-npe",
 168        .id             = -1,
 169        .num_resources  = ARRAY_SIZE(ixp4xx_npe_resources),
 170        .resource       = ixp4xx_npe_resources,
 171};
 172
 173static struct resource ixp4xx_qmgr_resources[] = {
 174        {
 175                .start = IXP4XX_QMGR_BASE_PHYS,
 176                .end = IXP4XX_QMGR_BASE_PHYS + 0x3fff,
 177                .flags = IORESOURCE_MEM,
 178        },
 179        {
 180                .start = IRQ_IXP4XX_QM1,
 181                .end = IRQ_IXP4XX_QM1,
 182                .flags = IORESOURCE_IRQ,
 183        },
 184        {
 185                .start = IRQ_IXP4XX_QM2,
 186                .end = IRQ_IXP4XX_QM2,
 187                .flags = IORESOURCE_IRQ,
 188        },
 189};
 190
 191static struct platform_device ixp4xx_qmgr_device = {
 192        .name           = "ixp4xx-qmgr",
 193        .id             = -1,
 194        .num_resources  = ARRAY_SIZE(ixp4xx_qmgr_resources),
 195        .resource       = ixp4xx_qmgr_resources,
 196};
 197
 198static struct platform_device *ixp4xx_devices[] __initdata = {
 199        &ixp4xx_npe_device,
 200        &ixp4xx_qmgr_device,
 201        &ixp4xx_gpio_device,
 202        &ixp4xx_udc_device,
 203};
 204
 205static struct resource ixp46x_i2c_resources[] = {
 206        [0] = {
 207                .start  = 0xc8011000,
 208                .end    = 0xc801101c,
 209                .flags  = IORESOURCE_MEM,
 210        },
 211        [1] = {
 212                .start  = IRQ_IXP4XX_I2C,
 213                .end    = IRQ_IXP4XX_I2C,
 214                .flags  = IORESOURCE_IRQ
 215        }
 216};
 217
 218/*
 219 * I2C controller. The IXP46x uses the same block as the IOP3xx, so
 220 * we just use the same device name.
 221 */
 222static struct platform_device ixp46x_i2c_controller = {
 223        .name           = "IOP3xx-I2C",
 224        .id             = 0,
 225        .num_resources  = 2,
 226        .resource       = ixp46x_i2c_resources
 227};
 228
 229static struct platform_device *ixp46x_devices[] __initdata = {
 230        &ixp46x_i2c_controller
 231};
 232
 233unsigned long ixp4xx_exp_bus_size;
 234EXPORT_SYMBOL(ixp4xx_exp_bus_size);
 235
 236void __init ixp4xx_sys_init(void)
 237{
 238        ixp4xx_exp_bus_size = SZ_16M;
 239
 240        platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices));
 241
 242        if (cpu_is_ixp46x()) {
 243                int region;
 244
 245                platform_add_devices(ixp46x_devices,
 246                                ARRAY_SIZE(ixp46x_devices));
 247
 248                for (region = 0; region < 7; region++) {
 249                        if((*(IXP4XX_EXP_REG(0x4 * region)) & 0x200)) {
 250                                ixp4xx_exp_bus_size = SZ_32M;
 251                                break;
 252                        }
 253                }
 254        }
 255
 256        printk("IXP4xx: Using %luMiB expansion bus window size\n",
 257                        ixp4xx_exp_bus_size >> 20);
 258}
 259
 260unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
 261EXPORT_SYMBOL(ixp4xx_timer_freq);
 262
 263void ixp4xx_restart(enum reboot_mode mode, const char *cmd)
 264{
 265        if (mode == REBOOT_SOFT) {
 266                /* Jump into ROM at address 0 */
 267                soft_restart(0);
 268        } else {
 269                /* Use on-chip reset capability */
 270
 271                /* set the "key" register to enable access to
 272                 * "timer" and "enable" registers
 273                 */
 274                *IXP4XX_OSWK = IXP4XX_WDT_KEY;
 275
 276                /* write 0 to the timer register for an immediate reset */
 277                *IXP4XX_OSWT = 0;
 278
 279                *IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
 280        }
 281}
 282
 283#ifdef CONFIG_PCI
 284static int ixp4xx_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
 285{
 286        return (dma_addr + size) > SZ_64M;
 287}
 288
 289static int ixp4xx_platform_notify_remove(struct device *dev)
 290{
 291        if (dev_is_pci(dev))
 292                dmabounce_unregister_dev(dev);
 293
 294        return 0;
 295}
 296#endif
 297
 298/*
 299 * Setup DMA mask to 64MB on PCI devices and 4 GB on all other things.
 300 */
 301static int ixp4xx_platform_notify(struct device *dev)
 302{
 303        dev->dma_mask = &dev->coherent_dma_mask;
 304
 305#ifdef CONFIG_PCI
 306        if (dev_is_pci(dev)) {
 307                dev->coherent_dma_mask = DMA_BIT_MASK(28); /* 64 MB */
 308                dmabounce_register_dev(dev, 2048, 4096, ixp4xx_needs_bounce);
 309                return 0;
 310        }
 311#endif
 312
 313        dev->coherent_dma_mask = DMA_BIT_MASK(32);
 314        return 0;
 315}
 316
 317int dma_set_coherent_mask(struct device *dev, u64 mask)
 318{
 319        if (dev_is_pci(dev))
 320                mask &= DMA_BIT_MASK(28); /* 64 MB */
 321
 322        if ((mask & DMA_BIT_MASK(28)) == DMA_BIT_MASK(28)) {
 323                dev->coherent_dma_mask = mask;
 324                return 0;
 325        }
 326
 327        return -EIO;            /* device wanted sub-64MB mask */
 328}
 329EXPORT_SYMBOL(dma_set_coherent_mask);
 330
 331#ifdef CONFIG_IXP4XX_INDIRECT_PCI
 332/*
 333 * In the case of using indirect PCI, we simply return the actual PCI
 334 * address and our read/write implementation use that to drive the
 335 * access registers. If something outside of PCI is ioremap'd, we
 336 * fallback to the default.
 337 */
 338
 339static void __iomem *ixp4xx_ioremap_caller(phys_addr_t addr, size_t size,
 340                                           unsigned int mtype, void *caller)
 341{
 342        if (!is_pci_memory(addr))
 343                return __arm_ioremap_caller(addr, size, mtype, caller);
 344
 345        return (void __iomem *)addr;
 346}
 347
 348static void ixp4xx_iounmap(volatile void __iomem *addr)
 349{
 350        if (!is_pci_memory((__force u32)addr))
 351                __iounmap(addr);
 352}
 353#endif
 354
 355void __init ixp4xx_init_early(void)
 356{
 357        platform_notify = ixp4xx_platform_notify;
 358#ifdef CONFIG_PCI
 359        platform_notify_remove = ixp4xx_platform_notify_remove;
 360#endif
 361#ifdef CONFIG_IXP4XX_INDIRECT_PCI
 362        arch_ioremap_caller = ixp4xx_ioremap_caller;
 363        arch_iounmap = ixp4xx_iounmap;
 364#endif
 365}
 366