mirror of
https://github.com/torvalds/linux.git
synced 2024-11-19 10:31:48 +00:00
bb413db591
Several at91sam9 chips need the alternate reset procedure to be sure to halt SDRAM smoothly before resetting the chip. This is an extension of previous patch "Fix AT91SAM9G20 reset" to all chips affected. Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
349 lines
8.0 KiB
C
349 lines
8.0 KiB
C
/*
|
|
* arch/arm/mach-at91/at91sam9261.c
|
|
*
|
|
* Copyright (C) 2005 SAN People
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/pm.h>
|
|
|
|
#include <asm/irq.h>
|
|
#include <asm/mach/arch.h>
|
|
#include <asm/mach/map.h>
|
|
#include <mach/cpu.h>
|
|
#include <mach/at91sam9261.h>
|
|
#include <mach/at91_pmc.h>
|
|
#include <mach/at91_rstc.h>
|
|
#include <mach/at91_shdwc.h>
|
|
|
|
#include "generic.h"
|
|
#include "clock.h"
|
|
|
|
static struct map_desc at91sam9261_io_desc[] __initdata = {
|
|
{
|
|
.virtual = AT91_VA_BASE_SYS,
|
|
.pfn = __phys_to_pfn(AT91_BASE_SYS),
|
|
.length = SZ_16K,
|
|
.type = MT_DEVICE,
|
|
},
|
|
};
|
|
|
|
static struct map_desc at91sam9261_sram_desc[] __initdata = {
|
|
{
|
|
.virtual = AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
|
|
.pfn = __phys_to_pfn(AT91SAM9261_SRAM_BASE),
|
|
.length = AT91SAM9261_SRAM_SIZE,
|
|
.type = MT_DEVICE,
|
|
},
|
|
};
|
|
|
|
static struct map_desc at91sam9g10_sram_desc[] __initdata = {
|
|
{
|
|
.virtual = AT91_IO_VIRT_BASE - AT91SAM9G10_SRAM_SIZE,
|
|
.pfn = __phys_to_pfn(AT91SAM9G10_SRAM_BASE),
|
|
.length = AT91SAM9G10_SRAM_SIZE,
|
|
.type = MT_DEVICE,
|
|
},
|
|
};
|
|
|
|
/* --------------------------------------------------------------------
|
|
* Clocks
|
|
* -------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* The peripheral clocks.
|
|
*/
|
|
static struct clk pioA_clk = {
|
|
.name = "pioA_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_PIOA,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk pioB_clk = {
|
|
.name = "pioB_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_PIOB,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk pioC_clk = {
|
|
.name = "pioC_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_PIOC,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk usart0_clk = {
|
|
.name = "usart0_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_US0,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk usart1_clk = {
|
|
.name = "usart1_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_US1,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk usart2_clk = {
|
|
.name = "usart2_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_US2,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk mmc_clk = {
|
|
.name = "mci_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_MCI,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk udc_clk = {
|
|
.name = "udc_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_UDP,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk twi_clk = {
|
|
.name = "twi_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_TWI,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk spi0_clk = {
|
|
.name = "spi0_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_SPI0,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk spi1_clk = {
|
|
.name = "spi1_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_SPI1,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk ssc0_clk = {
|
|
.name = "ssc0_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_SSC0,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk ssc1_clk = {
|
|
.name = "ssc1_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_SSC1,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk ssc2_clk = {
|
|
.name = "ssc2_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_SSC2,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk tc0_clk = {
|
|
.name = "tc0_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_TC0,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk tc1_clk = {
|
|
.name = "tc1_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_TC1,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk tc2_clk = {
|
|
.name = "tc2_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_TC2,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk ohci_clk = {
|
|
.name = "ohci_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_UHP,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
static struct clk lcdc_clk = {
|
|
.name = "lcdc_clk",
|
|
.pmc_mask = 1 << AT91SAM9261_ID_LCDC,
|
|
.type = CLK_TYPE_PERIPHERAL,
|
|
};
|
|
|
|
static struct clk *periph_clocks[] __initdata = {
|
|
&pioA_clk,
|
|
&pioB_clk,
|
|
&pioC_clk,
|
|
&usart0_clk,
|
|
&usart1_clk,
|
|
&usart2_clk,
|
|
&mmc_clk,
|
|
&udc_clk,
|
|
&twi_clk,
|
|
&spi0_clk,
|
|
&spi1_clk,
|
|
&ssc0_clk,
|
|
&ssc1_clk,
|
|
&ssc2_clk,
|
|
&tc0_clk,
|
|
&tc1_clk,
|
|
&tc2_clk,
|
|
&ohci_clk,
|
|
&lcdc_clk,
|
|
// irq0 .. irq2
|
|
};
|
|
|
|
/*
|
|
* The four programmable clocks.
|
|
* You must configure pin multiplexing to bring these signals out.
|
|
*/
|
|
static struct clk pck0 = {
|
|
.name = "pck0",
|
|
.pmc_mask = AT91_PMC_PCK0,
|
|
.type = CLK_TYPE_PROGRAMMABLE,
|
|
.id = 0,
|
|
};
|
|
static struct clk pck1 = {
|
|
.name = "pck1",
|
|
.pmc_mask = AT91_PMC_PCK1,
|
|
.type = CLK_TYPE_PROGRAMMABLE,
|
|
.id = 1,
|
|
};
|
|
static struct clk pck2 = {
|
|
.name = "pck2",
|
|
.pmc_mask = AT91_PMC_PCK2,
|
|
.type = CLK_TYPE_PROGRAMMABLE,
|
|
.id = 2,
|
|
};
|
|
static struct clk pck3 = {
|
|
.name = "pck3",
|
|
.pmc_mask = AT91_PMC_PCK3,
|
|
.type = CLK_TYPE_PROGRAMMABLE,
|
|
.id = 3,
|
|
};
|
|
|
|
/* HClocks */
|
|
static struct clk hck0 = {
|
|
.name = "hck0",
|
|
.pmc_mask = AT91_PMC_HCK0,
|
|
.type = CLK_TYPE_SYSTEM,
|
|
.id = 0,
|
|
};
|
|
static struct clk hck1 = {
|
|
.name = "hck1",
|
|
.pmc_mask = AT91_PMC_HCK1,
|
|
.type = CLK_TYPE_SYSTEM,
|
|
.id = 1,
|
|
};
|
|
|
|
static void __init at91sam9261_register_clocks(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
|
|
clk_register(periph_clocks[i]);
|
|
|
|
clk_register(&pck0);
|
|
clk_register(&pck1);
|
|
clk_register(&pck2);
|
|
clk_register(&pck3);
|
|
|
|
clk_register(&hck0);
|
|
clk_register(&hck1);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------
|
|
* GPIO
|
|
* -------------------------------------------------------------------- */
|
|
|
|
static struct at91_gpio_bank at91sam9261_gpio[] = {
|
|
{
|
|
.id = AT91SAM9261_ID_PIOA,
|
|
.offset = AT91_PIOA,
|
|
.clock = &pioA_clk,
|
|
}, {
|
|
.id = AT91SAM9261_ID_PIOB,
|
|
.offset = AT91_PIOB,
|
|
.clock = &pioB_clk,
|
|
}, {
|
|
.id = AT91SAM9261_ID_PIOC,
|
|
.offset = AT91_PIOC,
|
|
.clock = &pioC_clk,
|
|
}
|
|
};
|
|
|
|
static void at91sam9261_poweroff(void)
|
|
{
|
|
at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------
|
|
* AT91SAM9261 processor initialization
|
|
* -------------------------------------------------------------------- */
|
|
|
|
void __init at91sam9261_initialize(unsigned long main_clock)
|
|
{
|
|
/* Map peripherals */
|
|
iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
|
|
|
|
if (cpu_is_at91sam9g10())
|
|
iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
|
|
else
|
|
iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
|
|
|
|
|
|
at91_arch_reset = at91sam9_alt_reset;
|
|
pm_power_off = at91sam9261_poweroff;
|
|
at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
|
|
| (1 << AT91SAM9261_ID_IRQ2);
|
|
|
|
/* Init clock subsystem */
|
|
at91_clock_init(main_clock);
|
|
|
|
/* Register the processor-specific clocks */
|
|
at91sam9261_register_clocks();
|
|
|
|
/* Register GPIO subsystem */
|
|
at91_gpio_init(at91sam9261_gpio, 3);
|
|
}
|
|
|
|
/* --------------------------------------------------------------------
|
|
* Interrupt initialization
|
|
* -------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* The default interrupt priority levels (0 = lowest, 7 = highest).
|
|
*/
|
|
static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
|
7, /* Advanced Interrupt Controller */
|
|
7, /* System Peripherals */
|
|
1, /* Parallel IO Controller A */
|
|
1, /* Parallel IO Controller B */
|
|
1, /* Parallel IO Controller C */
|
|
0,
|
|
5, /* USART 0 */
|
|
5, /* USART 1 */
|
|
5, /* USART 2 */
|
|
0, /* Multimedia Card Interface */
|
|
2, /* USB Device Port */
|
|
6, /* Two-Wire Interface */
|
|
5, /* Serial Peripheral Interface 0 */
|
|
5, /* Serial Peripheral Interface 1 */
|
|
4, /* Serial Synchronous Controller 0 */
|
|
4, /* Serial Synchronous Controller 1 */
|
|
4, /* Serial Synchronous Controller 2 */
|
|
0, /* Timer Counter 0 */
|
|
0, /* Timer Counter 1 */
|
|
0, /* Timer Counter 2 */
|
|
2, /* USB Host port */
|
|
3, /* LCD Controller */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0, /* Advanced Interrupt Controller */
|
|
0, /* Advanced Interrupt Controller */
|
|
0, /* Advanced Interrupt Controller */
|
|
};
|
|
|
|
void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
|
|
{
|
|
if (!priority)
|
|
priority = at91sam9261_default_irq_priority;
|
|
|
|
/* Initialize the AIC interrupt controller */
|
|
at91_aic_init(priority);
|
|
|
|
/* Enable GPIO interrupts */
|
|
at91_gpio_irq_setup();
|
|
}
|