linux/arch/arm/mach-cns3xxx/core.c
<<
>>
Prefs
   1/*
   2 * Copyright 1999 - 2003 ARM Limited
   3 * Copyright 2000 Deep Blue Solutions Ltd
   4 * Copyright 2008 Cavium Networks
   5 *
   6 * This file is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License, Version 2, as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/init.h>
  12#include <linux/interrupt.h>
  13#include <linux/clockchips.h>
  14#include <linux/io.h>
  15#include <linux/irqchip/arm-gic.h>
  16#include <linux/of_platform.h>
  17#include <linux/platform_device.h>
  18#include <linux/usb/ehci_pdriver.h>
  19#include <linux/usb/ohci_pdriver.h>
  20#include <asm/mach/arch.h>
  21#include <asm/mach/map.h>
  22#include <asm/mach/time.h>
  23#include <asm/mach/irq.h>
  24#include <asm/hardware/cache-l2x0.h>
  25#include "cns3xxx.h"
  26#include "core.h"
  27#include "pm.h"
  28
  29static struct map_desc cns3xxx_io_desc[] __initdata = {
  30        {
  31                .virtual        = CNS3XXX_TC11MP_SCU_BASE_VIRT,
  32                .pfn            = __phys_to_pfn(CNS3XXX_TC11MP_SCU_BASE),
  33                .length         = SZ_8K,
  34                .type           = MT_DEVICE,
  35        }, {
  36                .virtual        = CNS3XXX_TIMER1_2_3_BASE_VIRT,
  37                .pfn            = __phys_to_pfn(CNS3XXX_TIMER1_2_3_BASE),
  38                .length         = SZ_4K,
  39                .type           = MT_DEVICE,
  40        }, {
  41                .virtual        = CNS3XXX_MISC_BASE_VIRT,
  42                .pfn            = __phys_to_pfn(CNS3XXX_MISC_BASE),
  43                .length         = SZ_4K,
  44                .type           = MT_DEVICE,
  45        }, {
  46                .virtual        = CNS3XXX_PM_BASE_VIRT,
  47                .pfn            = __phys_to_pfn(CNS3XXX_PM_BASE),
  48                .length         = SZ_4K,
  49                .type           = MT_DEVICE,
  50        },
  51};
  52
  53void __init cns3xxx_map_io(void)
  54{
  55        iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
  56}
  57
  58/* used by entry-macro.S */
  59void __init cns3xxx_init_irq(void)
  60{
  61        gic_init(0, 29, IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT),
  62                 IOMEM(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT));
  63}
  64
  65void cns3xxx_power_off(void)
  66{
  67        u32 __iomem *pm_base = IOMEM(CNS3XXX_PM_BASE_VIRT);
  68        u32 clkctrl;
  69
  70        printk(KERN_INFO "powering system down...\n");
  71
  72        clkctrl = readl(pm_base + PM_SYS_CLK_CTRL_OFFSET);
  73        clkctrl &= 0xfffff1ff;
  74        clkctrl |= (0x5 << 9);          /* Hibernate */
  75        writel(clkctrl, pm_base + PM_SYS_CLK_CTRL_OFFSET);
  76
  77}
  78
  79/*
  80 * Timer
  81 */
  82static void __iomem *cns3xxx_tmr1;
  83
  84static void cns3xxx_timer_set_mode(enum clock_event_mode mode,
  85                                   struct clock_event_device *clk)
  86{
  87        unsigned long ctrl = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
  88        int pclk = cns3xxx_cpu_clock() / 8;
  89        int reload;
  90
  91        switch (mode) {
  92        case CLOCK_EVT_MODE_PERIODIC:
  93                reload = pclk * 20 / (3 * HZ) * 0x25000;
  94                writel(reload, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
  95                ctrl |= (1 << 0) | (1 << 2) | (1 << 9);
  96                break;
  97        case CLOCK_EVT_MODE_ONESHOT:
  98                /* period set, and timer enabled in 'next_event' hook */
  99                ctrl |= (1 << 2) | (1 << 9);
 100                break;
 101        case CLOCK_EVT_MODE_UNUSED:
 102        case CLOCK_EVT_MODE_SHUTDOWN:
 103        default:
 104                ctrl = 0;
 105        }
 106
 107        writel(ctrl, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 108}
 109
 110static int cns3xxx_timer_set_next_event(unsigned long evt,
 111                                        struct clock_event_device *unused)
 112{
 113        unsigned long ctrl = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 114
 115        writel(evt, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
 116        writel(ctrl | (1 << 0), cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 117
 118        return 0;
 119}
 120
 121static struct clock_event_device cns3xxx_tmr1_clockevent = {
 122        .name           = "cns3xxx timer1",
 123        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 124        .set_mode       = cns3xxx_timer_set_mode,
 125        .set_next_event = cns3xxx_timer_set_next_event,
 126        .rating         = 350,
 127        .cpumask        = cpu_all_mask,
 128};
 129
 130static void __init cns3xxx_clockevents_init(unsigned int timer_irq)
 131{
 132        cns3xxx_tmr1_clockevent.irq = timer_irq;
 133        clockevents_config_and_register(&cns3xxx_tmr1_clockevent,
 134                                        (cns3xxx_cpu_clock() >> 3) * 1000000,
 135                                        0xf, 0xffffffff);
 136}
 137
 138/*
 139 * IRQ handler for the timer
 140 */
 141static irqreturn_t cns3xxx_timer_interrupt(int irq, void *dev_id)
 142{
 143        struct clock_event_device *evt = &cns3xxx_tmr1_clockevent;
 144        u32 __iomem *stat = cns3xxx_tmr1 + TIMER1_2_INTERRUPT_STATUS_OFFSET;
 145        u32 val;
 146
 147        /* Clear the interrupt */
 148        val = readl(stat);
 149        writel(val & ~(1 << 2), stat);
 150
 151        evt->event_handler(evt);
 152
 153        return IRQ_HANDLED;
 154}
 155
 156static struct irqaction cns3xxx_timer_irq = {
 157        .name           = "timer",
 158        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 159        .handler        = cns3xxx_timer_interrupt,
 160};
 161
 162/*
 163 * Set up the clock source and clock events devices
 164 */
 165static void __init __cns3xxx_timer_init(unsigned int timer_irq)
 166{
 167        u32 val;
 168        u32 irq_mask;
 169
 170        /*
 171         * Initialise to a known state (all timers off)
 172         */
 173
 174        /* disable timer1 and timer2 */
 175        writel(0, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 176        /* stop free running timer3 */
 177        writel(0, cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
 178
 179        /* timer1 */
 180        writel(0x5C800, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
 181        writel(0x5C800, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
 182
 183        writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V1_OFFSET);
 184        writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V2_OFFSET);
 185
 186        /* mask irq, non-mask timer1 overflow */
 187        irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
 188        irq_mask &= ~(1 << 2);
 189        irq_mask |= 0x03;
 190        writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
 191
 192        /* down counter */
 193        val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 194        val |= (1 << 9);
 195        writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 196
 197        /* timer2 */
 198        writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V1_OFFSET);
 199        writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V2_OFFSET);
 200
 201        /* mask irq */
 202        irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
 203        irq_mask |= ((1 << 3) | (1 << 4) | (1 << 5));
 204        writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
 205
 206        /* down counter */
 207        val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 208        val |= (1 << 10);
 209        writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 210
 211        /* Make irqs happen for the system timer */
 212        setup_irq(timer_irq, &cns3xxx_timer_irq);
 213
 214        cns3xxx_clockevents_init(timer_irq);
 215}
 216
 217void __init cns3xxx_timer_init(void)
 218{
 219        cns3xxx_tmr1 = IOMEM(CNS3XXX_TIMER1_2_3_BASE_VIRT);
 220
 221        __cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0);
 222}
 223
 224#ifdef CONFIG_CACHE_L2X0
 225
 226void __init cns3xxx_l2x0_init(void)
 227{
 228        void __iomem *base = ioremap(CNS3XXX_L2C_BASE, SZ_4K);
 229        u32 val;
 230
 231        if (WARN_ON(!base))
 232                return;
 233
 234        /*
 235         * Tag RAM Control register
 236         *
 237         * bit[10:8]    - 1 cycle of write accesses latency
 238         * bit[6:4]     - 1 cycle of read accesses latency
 239         * bit[3:0]     - 1 cycle of setup latency
 240         *
 241         * 1 cycle of latency for setup, read and write accesses
 242         */
 243        val = readl(base + L2X0_TAG_LATENCY_CTRL);
 244        val &= 0xfffff888;
 245        writel(val, base + L2X0_TAG_LATENCY_CTRL);
 246
 247        /*
 248         * Data RAM Control register
 249         *
 250         * bit[10:8]    - 1 cycles of write accesses latency
 251         * bit[6:4]     - 1 cycles of read accesses latency
 252         * bit[3:0]     - 1 cycle of setup latency
 253         *
 254         * 1 cycle of latency for setup, read and write accesses
 255         */
 256        val = readl(base + L2X0_DATA_LATENCY_CTRL);
 257        val &= 0xfffff888;
 258        writel(val, base + L2X0_DATA_LATENCY_CTRL);
 259
 260        /* 32 KiB, 8-way, parity disable */
 261        l2x0_init(base, 0x00540000, 0xfe000fff);
 262}
 263
 264#endif /* CONFIG_CACHE_L2X0 */
 265
 266static int csn3xxx_usb_power_on(struct platform_device *pdev)
 267{
 268        /*
 269         * EHCI and OHCI share the same clock and power,
 270         * resetting twice would cause the 1st controller been reset.
 271         * Therefore only do power up  at the first up device, and
 272         * power down at the last down device.
 273         *
 274         * Set USB AHB INCR length to 16
 275         */
 276        if (atomic_inc_return(&usb_pwr_ref) == 1) {
 277                cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB);
 278                cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
 279                cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST);
 280                __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)),
 281                        MISC_CHIP_CONFIG_REG);
 282        }
 283
 284        return 0;
 285}
 286
 287static void csn3xxx_usb_power_off(struct platform_device *pdev)
 288{
 289        /*
 290         * EHCI and OHCI share the same clock and power,
 291         * resetting twice would cause the 1st controller been reset.
 292         * Therefore only do power up  at the first up device, and
 293         * power down at the last down device.
 294         */
 295        if (atomic_dec_return(&usb_pwr_ref) == 0)
 296                cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST);
 297}
 298
 299static struct usb_ehci_pdata cns3xxx_usb_ehci_pdata = {
 300        .power_on       = csn3xxx_usb_power_on,
 301        .power_off      = csn3xxx_usb_power_off,
 302};
 303
 304static struct usb_ohci_pdata cns3xxx_usb_ohci_pdata = {
 305        .num_ports      = 1,
 306        .power_on       = csn3xxx_usb_power_on,
 307        .power_off      = csn3xxx_usb_power_off,
 308};
 309
 310static struct of_dev_auxdata cns3xxx_auxdata[] __initconst = {
 311        { "intel,usb-ehci", CNS3XXX_USB_BASE, "ehci-platform", &cns3xxx_usb_ehci_pdata },
 312        { "intel,usb-ohci", CNS3XXX_USB_OHCI_BASE, "ohci-platform", &cns3xxx_usb_ohci_pdata },
 313        { "cavium,cns3420-ahci", CNS3XXX_SATA2_BASE, "ahci", NULL },
 314        { "cavium,cns3420-sdhci", CNS3XXX_SDIO_BASE, "ahci", NULL },
 315        {},
 316};
 317
 318static void __init cns3xxx_init(void)
 319{
 320        struct device_node *dn;
 321
 322        cns3xxx_l2x0_init();
 323
 324        dn = of_find_compatible_node(NULL, NULL, "cavium,cns3420-ahci");
 325        if (of_device_is_available(dn)) {
 326                u32 tmp;
 327        
 328                tmp = __raw_readl(MISC_SATA_POWER_MODE);
 329                tmp |= 0x1 << 16; /* Disable SATA PHY 0 from SLUMBER Mode */
 330                tmp |= 0x1 << 17; /* Disable SATA PHY 1 from SLUMBER Mode */
 331                __raw_writel(tmp, MISC_SATA_POWER_MODE);
 332        
 333                /* Enable SATA PHY */
 334                cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY0);
 335                cns3xxx_pwr_power_up(0x1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_SATA_PHY1);
 336        
 337                /* Enable SATA Clock */
 338                cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_SATA);
 339        
 340                /* De-Asscer SATA Reset */
 341                cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SATA));
 342        }
 343
 344        dn = of_find_compatible_node(NULL, NULL, "cavium,cns3420-sdhci");
 345        if (of_device_is_available(dn)) {
 346                u32 __iomem *gpioa = IOMEM(CNS3XXX_MISC_BASE_VIRT + 0x0014);
 347                u32 gpioa_pins = __raw_readl(gpioa);
 348        
 349                /* MMC/SD pins share with GPIOA */
 350                gpioa_pins |= 0x1fff0004;
 351                __raw_writel(gpioa_pins, gpioa);
 352        
 353                cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SDIO));
 354                cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SDIO));
 355        }
 356
 357        pm_power_off = cns3xxx_power_off;
 358
 359        of_platform_populate(NULL, of_default_bus_match_table,
 360                        cns3xxx_auxdata, NULL);
 361}
 362
 363static const char *cns3xxx_dt_compat[] __initdata = {
 364        "cavium,cns3410",
 365        "cavium,cns3420",
 366        NULL,
 367};
 368
 369DT_MACHINE_START(CNS3XXX_DT, "Cavium Networks CNS3xxx")
 370        .dt_compat      = cns3xxx_dt_compat,
 371        .nr_irqs        = NR_IRQS_CNS3XXX,
 372        .map_io         = cns3xxx_map_io,
 373        .init_irq       = cns3xxx_init_irq,
 374        .init_time      = cns3xxx_timer_init,
 375        .init_machine   = cns3xxx_init,
 376        .restart        = cns3xxx_restart,
 377MACHINE_END
 378