arm-soc: support for new SoCs

Three new system-on-chip models are supported: the st-ericsson u9540
 in ux500, the sam9n12 in at91 and the emma ev2 in shmobile.
 
 Emma is a little bit special because it is completely unrelated to
 the classic shmobile models, but the new Renesas rmobile SoCs are a
 combination of things from both Emma and shmobile, so it was decided to
 have them all live in one directory.
 
 This also contains updates to existing shmobile soc code as well as some
 related board changes due to dependencies.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJPuerfAAoJEIwa5zzehBx3hi4P/AsoiLW4VqN67zMmiaGC5Nwe
 X5nAeaaU0Oo4I9W2QD37V0BShk+yOE9xx7I0TOx7xE6/DpkJ3DhNlUOIvJSbtVD9
 vOHF0pSu4huwmqMQmSS8qk5imYMVNGcDmNPVJsPdMCpC2PeCjNY5PxzX4PA18GxZ
 9WaPClAP2vqSf/WewiFs73HE70TPL9DuMnAaA2QLBfeu6Cj5K401sc0sdJnBKJFc
 W7T8qo1LJ98wEWeGW1Qks2mhtwlRf3S20t6aYQi0Bm9znaHMRomdaWdkrXLUYxiO
 l8EHkCzgggXhdaqvqp15M3AFGgDsw+713UQ0n7tMGvIXv+Oc9ctriK0vcjIXHzH/
 Ifz+4KvqYPo47ha0vSUpoRx29ThXO/zKDlzOUdh48JUWqBN6IDw+5H93ghI5SWGu
 2h9RuAHIRxumtVe1Qb2dh2SzByxfqJJs7fkASXqWfucYgEi4vhylQdS7akCZ5ycq
 35MOTS3v8rwxemTAR0NZKguRwVfUDnHGpyehumY5b/dp8nF0uHNaF8dRpnDC04Ty
 4AHSquNmujQ0fqSJfcDCNT9V4vhrbdnW0YqhpCNFYLWBWnybJwjWDriWgt3Cc9tL
 BMApWGprknKjxH/LeoZHIr0cHGjhZ0iRgoX+av7mPbNUcW/T64HEIs1Yyo4dbE2w
 ffQN5xWomW+8VdZ1qf+w
 =5TAz
 -----END PGP SIGNATURE-----

Merge tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull support for new arm SoCs from Olof Johansson:
 "Three new system-on-chip models are supported: the st-ericsson u9540
  in ux500, the sam9n12 in at91 and the emma ev2 in shmobile.

  Emma is a little bit special because it is completely unrelated to the
  classic shmobile models, but the new Renesas rmobile SoCs are a
  combination of things from both Emma and shmobile, so it was decided
  to have them all live in one directory.

  This also contains updates to existing shmobile soc code as well as
  some related board changes due to dependencies."

* tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (23 commits)
  mach-shmobile: Use DT_MACHINE for KZM9D V3
  mach-shmobile: Emma Mobile EV2 DT support V3
  mach-shmobile: KZM9D board Ethernet support V3
  mach-shmobile: Emma Mobile EV2 GPIO support V3
  mach-shmobile: Emma Mobile EV2 SMP support V3
  mach-shmobile: KZM9D board support V3
  mach-shmobile: Emma Mobile EV2 SoC base support V3
  gpio: Emma Mobile GPIO driver V2
  ARM: mach-shmobile: sh73a0: fixup PINT/IRQ16-IRQ31 irq number conflict
  ARM: mach-shmobile: clock-r8a7740: use followparent_recalc on usb24s
  ARM: mach-shmobile: clock-r8a7740: add MMCIF clock
  ARM: mach-shmobile: clock-r8a7740: add SDHI clock
  ARM: mach-shmobile: clock-r8a7740: add USB clock
  ARM: mach-shmobile: clock-r8a7740: add FSI clock
  ARM: mach-shmobile: r8a7740: cleanup I2C workaround method
  ARM: mach-shmobile: r8a7740: add gpio_irq support
  ARM: mach-shmobile: sh7372: Add FSI DMAEngine support
  ARM / mach-shmobile: Use preset_lpj with calibrate_delay()
  ARM: ux500: ioremap differences for DB9540
  ARM: ux500: core U9540 support
  ...
This commit is contained in:
Linus Torvalds 2012-05-22 09:32:42 -07:00
commit 9f639269ed
47 changed files with 2439 additions and 36 deletions

View File

@ -0,0 +1,221 @@
/*
* at91sam9n12.dtsi - Device Tree include file for AT91SAM9N12 SoC
*
* Copyright (C) 2012 Atmel,
* 2012 Hong Xu <hong.xu@atmel.com>
*
* Licensed under GPLv2 or later.
*/
/include/ "skeleton.dtsi"
/ {
model = "Atmel AT91SAM9N12 SoC";
compatible = "atmel,at91sam9n12";
interrupt-parent = <&aic>;
aliases {
serial0 = &dbgu;
serial1 = &usart0;
serial2 = &usart1;
serial3 = &usart2;
serial4 = &usart3;
gpio0 = &pioA;
gpio1 = &pioB;
gpio2 = &pioC;
gpio3 = &pioD;
tcb0 = &tcb0;
tcb1 = &tcb1;
};
cpus {
cpu@0 {
compatible = "arm,arm926ejs";
};
};
memory {
reg = <0x20000000 0x10000000>;
};
ahb {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
apb {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
aic: interrupt-controller@fffff000 {
#interrupt-cells = <2>;
compatible = "atmel,at91rm9200-aic";
interrupt-controller;
reg = <0xfffff000 0x200>;
};
ramc0: ramc@ffffe800 {
compatible = "atmel,at91sam9g45-ddramc";
reg = <0xffffe800 0x200>;
};
pmc: pmc@fffffc00 {
compatible = "atmel,at91rm9200-pmc";
reg = <0xfffffc00 0x100>;
};
rstc@fffffe00 {
compatible = "atmel,at91sam9g45-rstc";
reg = <0xfffffe00 0x10>;
};
pit: timer@fffffe30 {
compatible = "atmel,at91sam9260-pit";
reg = <0xfffffe30 0xf>;
interrupts = <1 4>;
};
shdwc@fffffe10 {
compatible = "atmel,at91sam9x5-shdwc";
reg = <0xfffffe10 0x10>;
};
tcb0: timer@f8008000 {
compatible = "atmel,at91sam9x5-tcb";
reg = <0xf8008000 0x100>;
interrupts = <17 4>;
};
tcb1: timer@f800c000 {
compatible = "atmel,at91sam9x5-tcb";
reg = <0xf800c000 0x100>;
interrupts = <17 4>;
};
dma: dma-controller@ffffec00 {
compatible = "atmel,at91sam9g45-dma";
reg = <0xffffec00 0x200>;
interrupts = <20 4>;
};
pioA: gpio@fffff400 {
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioB: gpio@fffff600 {
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff600 0x100>;
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioC: gpio@fffff800 {
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff800 0x100>;
interrupts = <3 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
pioD: gpio@fffffa00 {
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffffa00 0x100>;
interrupts = <3 4>;
#gpio-cells = <2>;
gpio-controller;
interrupt-controller;
};
dbgu: serial@fffff200 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffff200 0x200>;
interrupts = <1 4>;
status = "disabled";
};
usart0: serial@f801c000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xf801c000 0x4000>;
interrupts = <5 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
};
usart1: serial@f8020000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xf8020000 0x4000>;
interrupts = <6 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
};
usart2: serial@f8024000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xf8024000 0x4000>;
interrupts = <7 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
};
usart3: serial@f8028000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xf8028000 0x4000>;
interrupts = <8 4>;
atmel,use-dma-rx;
atmel,use-dma-tx;
status = "disabled";
};
};
nand0: nand@40000000 {
compatible = "atmel,at91rm9200-nand";
#address-cells = <1>;
#size-cells = <1>;
reg = < 0x40000000 0x10000000
0xffffe000 0x00000600
0xffffe600 0x00000200
0x00100000 0x00100000
>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
gpios = <&pioD 5 0
&pioD 4 0
0
>;
status = "disabled";
};
usb0: ohci@00500000 {
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
reg = <0x00500000 0x00100000>;
interrupts = <22 4>;
status = "disabled";
};
};
i2c@0 {
compatible = "i2c-gpio";
gpios = <&pioA 30 0 /* sda */
&pioA 31 0 /* scl */
>;
i2c-gpio,sda-open-drain;
i2c-gpio,scl-open-drain;
i2c-gpio,delay-us = <2>; /* ~100 kHz */
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
};

View File

@ -0,0 +1,84 @@
/*
* at91sam9n12ek.dts - Device Tree file for AT91SAM9N12-EK board
*
* Copyright (C) 2012 Atmel,
* 2012 Hong Xu <hong.xu@atmel.com>
*
* Licensed under GPLv2 or later.
*/
/dts-v1/;
/include/ "at91sam9n12.dtsi"
/ {
model = "Atmel AT91SAM9N12-EK";
compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9";
chosen {
bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
};
memory {
reg = <0x20000000 0x10000000>;
};
clocks {
#address-cells = <1>;
#size-cells = <1>;
ranges;
main_clock: clock@0 {
compatible = "atmel,osc", "fixed-clock";
clock-frequency = <16000000>;
};
};
ahb {
apb {
dbgu: serial@fffff200 {
status = "okay";
};
};
nand0: nand@40000000 {
nand-bus-width = <8>;
nand-ecc-mode = "soft";
nand-on-flash-bbt;
status = "okay";
};
};
leds {
compatible = "gpio-leds";
d8 {
label = "d8";
gpios = <&pioB 4 1>;
linux,default-trigger = "mmc0";
};
d9 {
label = "d6";
gpios = <&pioB 5 1>;
linux,default-trigger = "nand-disk";
};
d10 {
label = "d7";
gpios = <&pioB 6 0>;
linux,default-trigger = "heartbeat";
};
};
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
enter {
label = "Enter";
gpios = <&pioB 4 1>;
linux,code = <28>;
gpio-key,wakeup;
};
};
};

View File

@ -0,0 +1,26 @@
/*
* Device Tree Source for the KZM9D board
*
* Copyright (C) 2012 Renesas Solutions Corp.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
/dts-v1/;
/include/ "emev2.dtsi"
/ {
model = "EMEV2 KZM9D Board";
compatible = "renesas,kzm9d", "renesas,emev2";
memory {
device_type = "memory";
reg = <0x40000000 0x8000000>;
};
chosen {
bootargs = "console=ttyS1,115200n81";
};
};

View File

@ -0,0 +1,63 @@
/*
* Device Tree Source for the EMEV2 SoC
*
* Copyright (C) 2012 Renesas Solutions Corp.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
/include/ "skeleton.dtsi"
/ {
compatible = "renesas,emev2";
interrupt-parent = <&gic>;
cpus {
cpu@0 {
compatible = "arm,cortex-a9";
};
cpu@1 {
compatible = "arm,cortex-a9";
};
};
gic: interrupt-controller@e0020000 {
compatible = "arm,cortex-a9-gic";
interrupt-controller;
#interrupt-cells = <3>;
reg = <0xe0028000 0x1000>,
<0xe0020000 0x0100>;
};
sti@e0180000 {
compatible = "renesas,em-sti";
reg = <0xe0180000 0x54>;
interrupts = <0 125 0>;
};
uart@e1020000 {
compatible = "renesas,em-uart";
reg = <0xe1020000 0x38>;
interrupts = <0 8 0>;
};
uart@e1030000 {
compatible = "renesas,em-uart";
reg = <0xe1030000 0x38>;
interrupts = <0 9 0>;
};
uart@e1040000 {
compatible = "renesas,em-uart";
reg = <0xe1040000 0x38>;
interrupts = <0 10 0>;
};
uart@e1050000 {
compatible = "renesas,em-uart";
reg = <0xe1050000 0x38>;
interrupts = <0 11 0>;
};
};

View File

@ -91,6 +91,14 @@ config SOC_AT91SAM9X5
This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
and AT91SAM9X35.
config SOC_AT91SAM9N12
bool "AT91SAM9N12 family"
select SOC_AT91SAM9
select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL
help
Select this if you are using Atmel's AT91SAM9N12 SoC.
choice
prompt "Atmel AT91 Processor Devices for non DT boards"

View File

@ -18,6 +18,7 @@ obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o
obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o
obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o
obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o
obj-$(CONFIG_SOC_AT91SAM9N12) += at91sam9n12.o
obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o
obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o

View File

@ -30,5 +30,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
# sam9g45
dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
# sam9n12
dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
# sam9x5
dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb

View File

@ -0,0 +1,233 @@
/*
* SoC specific setup code for the AT91SAM9N12
*
* Copyright (C) 2012 Atmel Corporation.
*
* Licensed under GPLv2 or later.
*/
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/at91sam9n12.h>
#include <mach/at91_pmc.h>
#include <mach/cpu.h>
#include <mach/board.h>
#include "soc.h"
#include "generic.h"
#include "clock.h"
#include "sam9_smc.h"
/* --------------------------------------------------------------------
* Clocks
* -------------------------------------------------------------------- */
/*
* The peripheral clocks.
*/
static struct clk pioAB_clk = {
.name = "pioAB_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_PIOAB,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk pioCD_clk = {
.name = "pioCD_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_PIOCD,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk usart0_clk = {
.name = "usart0_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_USART0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk usart1_clk = {
.name = "usart1_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_USART1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk usart2_clk = {
.name = "usart2_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_USART2,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk usart3_clk = {
.name = "usart3_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_USART3,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk twi0_clk = {
.name = "twi0_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_TWI0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk twi1_clk = {
.name = "twi1_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_TWI1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk mmc_clk = {
.name = "mci_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_MCI,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk spi0_clk = {
.name = "spi0_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_SPI0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk spi1_clk = {
.name = "spi1_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_SPI1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk uart0_clk = {
.name = "uart0_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_UART0,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk uart1_clk = {
.name = "uart1_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_UART1,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk tcb_clk = {
.name = "tcb_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_TCB,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk pwm_clk = {
.name = "pwm_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_PWM,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk adc_clk = {
.name = "adc_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_ADC,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk dma_clk = {
.name = "dma_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_DMA,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk uhp_clk = {
.name = "uhp",
.pmc_mask = 1 << AT91SAM9N12_ID_UHP,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk udp_clk = {
.name = "udp_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_UDP,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk lcdc_clk = {
.name = "lcdc_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_LCDC,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk ssc_clk = {
.name = "ssc_clk",
.pmc_mask = 1 << AT91SAM9N12_ID_SSC,
.type = CLK_TYPE_PERIPHERAL,
};
static struct clk *periph_clocks[] __initdata = {
&pioAB_clk,
&pioCD_clk,
&usart0_clk,
&usart1_clk,
&usart2_clk,
&usart3_clk,
&twi0_clk,
&twi1_clk,
&mmc_clk,
&spi0_clk,
&spi1_clk,
&lcdc_clk,
&uart0_clk,
&uart1_clk,
&tcb_clk,
&pwm_clk,
&adc_clk,
&dma_clk,
&uhp_clk,
&udp_clk,
&ssc_clk,
};
static struct clk_lookup periph_clocks_lookups[] = {
/* lookup table for DT entries */
CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
CLKDEV_CON_ID("pioA", &pioAB_clk),
CLKDEV_CON_ID("pioB", &pioAB_clk),
CLKDEV_CON_ID("pioC", &pioCD_clk),
CLKDEV_CON_ID("pioD", &pioCD_clk),
/* additional fake clock for macb_hclk */
CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
};
/*
* The two 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 void __init at91sam9n12_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);
clkdev_add_table(periph_clocks_lookups,
ARRAY_SIZE(periph_clocks_lookups));
}
/* --------------------------------------------------------------------
* AT91SAM9N12 processor initialization
* -------------------------------------------------------------------- */
static void __init at91sam9n12_map_io(void)
{
at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
}
void __init at91sam9n12_initialize(void)
{
at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
/* Register GPIO subsystem (using DT) */
at91_gpio_init(NULL, 0);
}
struct at91_init_soc __initdata at91sam9n12_soc = {
.map_io = at91sam9n12_map_io,
.register_clocks = at91sam9n12_register_clocks,
.init = at91sam9n12_initialize,
};

View File

@ -58,13 +58,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
|| cpu_is_at91sam9g45() \
|| cpu_is_at91sam9x5())
|| cpu_is_at91sam9x5() \
|| cpu_is_at91sam9n12())
#define cpu_has_300M_plla() (cpu_is_at91sam9g10())
#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
|| cpu_is_at91sam9g45() \
|| cpu_is_at91sam9x5()))
|| cpu_is_at91sam9x5() \
|| cpu_is_at91sam9n12()))
#define cpu_has_upll() (cpu_is_at91sam9g45() \
|| cpu_is_at91sam9x5())
@ -78,12 +80,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
|| cpu_is_at91sam9x5()))
#define cpu_has_plladiv2() (cpu_is_at91sam9g45() \
|| cpu_is_at91sam9x5())
|| cpu_is_at91sam9x5() \
|| cpu_is_at91sam9n12())
#define cpu_has_mdiv3() (cpu_is_at91sam9g45() \
|| cpu_is_at91sam9x5())
|| cpu_is_at91sam9x5() \
|| cpu_is_at91sam9n12())
#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5())
#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \
|| cpu_is_at91sam9n12())
static LIST_HEAD(clocks);
static DEFINE_SPINLOCK(clk_lock);

View File

@ -0,0 +1,60 @@
/*
* SoC specific header file for the AT91SAM9N12
*
* Copyright (C) 2012 Atmel Corporation
*
* Common definitions, based on AT91SAM9N12 SoC datasheet
*
* Licensed under GPLv2 or later
*/
#ifndef _AT91SAM9N12_H_
#define _AT91SAM9N12_H_
/*
* Peripheral identifiers/interrupts.
*/
#define AT91SAM9N12_ID_PIOAB 2 /* Parallel I/O Controller A and B */
#define AT91SAM9N12_ID_PIOCD 3 /* Parallel I/O Controller C and D */
#define AT91SAM9N12_ID_FUSE 4 /* FUSE Controller */
#define AT91SAM9N12_ID_USART0 5 /* USART 0 */
#define AT91SAM9N12_ID_USART1 6 /* USART 1 */
#define AT91SAM9N12_ID_USART2 7 /* USART 2 */
#define AT91SAM9N12_ID_USART3 8 /* USART 3 */
#define AT91SAM9N12_ID_TWI0 9 /* Two-Wire Interface 0 */
#define AT91SAM9N12_ID_TWI1 10 /* Two-Wire Interface 1 */
#define AT91SAM9N12_ID_MCI 12 /* High Speed Multimedia Card Interface */
#define AT91SAM9N12_ID_SPI0 13 /* Serial Peripheral Interface 0 */
#define AT91SAM9N12_ID_SPI1 14 /* Serial Peripheral Interface 1 */
#define AT91SAM9N12_ID_UART0 15 /* UART 0 */
#define AT91SAM9N12_ID_UART1 16 /* UART 1 */
#define AT91SAM9N12_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */
#define AT91SAM9N12_ID_PWM 18 /* Pulse Width Modulation Controller */
#define AT91SAM9N12_ID_ADC 19 /* ADC Controller */
#define AT91SAM9N12_ID_DMA 20 /* DMA Controller */
#define AT91SAM9N12_ID_UHP 22 /* USB Host High Speed */
#define AT91SAM9N12_ID_UDP 23 /* USB Device High Speed */
#define AT91SAM9N12_ID_LCDC 25 /* LCD Controller */
#define AT91SAM9N12_ID_ISI 25 /* Image Sensor Interface */
#define AT91SAM9N12_ID_SSC 28 /* Synchronous Serial Controller */
#define AT91SAM9N12_ID_TRNG 30 /* TRNG */
#define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */
/*
* User Peripheral physical base addresses.
*/
#define AT91SAM9N12_BASE_USART0 0xf801c000
#define AT91SAM9N12_BASE_USART1 0xf8020000
#define AT91SAM9N12_BASE_USART2 0xf8024000
#define AT91SAM9N12_BASE_USART3 0xf8028000
/*
* Internal Memory.
*/
#define AT91SAM9N12_SRAM_BASE 0x00300000 /* Internal SRAM base address */
#define AT91SAM9N12_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */
#define AT91SAM9N12_ROM_BASE 0x00100000 /* Internal ROM base address */
#define AT91SAM9N12_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */
#endif

View File

@ -0,0 +1,53 @@
/*
* Matrix-centric header file for the AT91SAM9N12
*
* Copyright (C) 2012 Atmel Corporation.
*
* Only EBI related registers.
* Write Protect register definitions may be useful.
*
* Licensed under GPLv2 or later.
*/
#ifndef _AT91SAM9N12_MATRIX_H_
#define _AT91SAM9N12_MATRIX_H_
#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x118) /* EBI Chip Select Assignment Register */
#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */
#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1)
#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1)
#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */
#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3)
#define AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH (1 << 3)
#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */
#define AT91_MATRIX_EBI_DBPU_ON (0 << 8)
#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8)
#define AT91_MATRIX_EBI_VDDIOMSEL (1 << 16) /* Memory voltage selection */
#define AT91_MATRIX_EBI_VDDIOMSEL_1_8V (0 << 16)
#define AT91_MATRIX_EBI_VDDIOMSEL_3_3V (1 << 16)
#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */
#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17)
#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17)
#define AT91_MATRIX_EBI_DDR_IOSR (1 << 18) /* DDR2 dedicated port I/O slew rate selection */
#define AT91_MATRIX_EBI_DDR_IOSR_REDUCED (0 << 18)
#define AT91_MATRIX_EBI_DDR_IOSR_NORMAL (1 << 18)
#define AT91_MATRIX_NFD0_SELECT (1 << 24) /* NAND Flash Data Bus Selection */
#define AT91_MATRIX_NFD0_ON_D0 (0 << 24)
#define AT91_MATRIX_NFD0_ON_D16 (1 << 24)
#define AT91_MATRIX_DDR_MP_EN (1 << 25) /* DDR Multi-port Enable */
#define AT91_MATRIX_MP_OFF (0 << 25)
#define AT91_MATRIX_MP_ON (1 << 25)
#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */
#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */
#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0)
#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0)
#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */
#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */
#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */
#define AT91_MATRIX_WPSR_NO_WPV (0 << 0)
#define AT91_MATRIX_WPSR_WPV (1 << 0)
#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */
#endif

View File

@ -25,6 +25,7 @@
#define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */
#define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */
#define ARCH_ID_AT91SAM9X5 0x819a05a0
#define ARCH_ID_AT91SAM9N12 0x819a07a0
#define ARCH_ID_AT91SAM9XE128 0x329973a0
#define ARCH_ID_AT91SAM9XE256 0x329a93a0
@ -71,6 +72,9 @@ enum at91_soc_type {
/* SAM9X5 */
AT91_SOC_SAM9X5,
/* SAM9N12 */
AT91_SOC_SAM9N12,
/* Unknown type */
AT91_SOC_NONE
};
@ -177,6 +181,12 @@ static inline int at91_soc_is_detected(void)
#define cpu_is_at91sam9x25() (0)
#endif
#ifdef CONFIG_SOC_AT91SAM9N12
#define cpu_is_at91sam9n12() (at91_soc_initdata.type == AT91_SOC_SAM9N12)
#else
#define cpu_is_at91sam9n12() (0)
#endif
/*
* Since this is ARM, we will never run on any AVR32 CPU. But these
* definitions may reduce clutter in common drivers.

View File

@ -32,6 +32,7 @@
#include <mach/at91sam9rl.h>
#include <mach/at91sam9g45.h>
#include <mach/at91sam9x5.h>
#include <mach/at91sam9n12.h>
/*
* On all at91 except rm9200 and x40 have the System Controller starts

View File

@ -143,6 +143,11 @@ static void __init soc_detect(u32 dbgu_base)
at91_soc_initdata.type = AT91_SOC_SAM9X5;
at91_boot_soc = at91sam9x5_soc;
break;
case ARCH_ID_AT91SAM9N12:
at91_soc_initdata.type = AT91_SOC_SAM9N12;
at91_boot_soc = at91sam9n12_soc;
break;
}
/* at91sam9g10 */
@ -210,6 +215,7 @@ static const char *soc_name[] = {
[AT91_SOC_SAM9G45] = "at91sam9g45",
[AT91_SOC_SAM9RL] = "at91sam9rl",
[AT91_SOC_SAM9X5] = "at91sam9x5",
[AT91_SOC_SAM9N12] = "at91sam9n12",
[AT91_SOC_NONE] = "Unknown"
};

View File

@ -20,6 +20,7 @@ extern struct at91_init_soc at91sam9263_soc;
extern struct at91_init_soc at91sam9g45_soc;
extern struct at91_init_soc at91sam9rl_soc;
extern struct at91_init_soc at91sam9x5_soc;
extern struct at91_init_soc at91sam9n12_soc;
static inline int at91_soc_is_enabled(void)
{
@ -53,3 +54,7 @@ static inline int at91_soc_is_enabled(void)
#if !defined(CONFIG_SOC_AT91SAM9X5)
#define at91sam9x5_soc at91_boot_soc
#endif
#if !defined(CONFIG_SOC_AT91SAM9N12)
#define at91sam9n12_soc at91_boot_soc
#endif

View File

@ -41,6 +41,12 @@ config ARCH_R8A7779
select ARM_GIC
select ARCH_WANT_OPTIONAL_GPIOLIB
config ARCH_EMEV2
bool "Emma Mobile EV2"
select CPU_V7
select ARM_GIC
select ARCH_WANT_OPTIONAL_GPIOLIB
comment "SH-Mobile Board Type"
config MACH_G3EVM
@ -98,6 +104,11 @@ config MACH_MARZEN
depends on ARCH_R8A7779
select ARCH_REQUIRE_GPIOLIB
config MACH_KZM9D
bool "KZM9D board"
depends on ARCH_EMEV2
select USE_OF
comment "SH-Mobile System Configuration"
config CPU_HAS_INTEVT

View File

@ -12,12 +12,14 @@ obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o
# SMP objects
smp-y := platsmp.o headsmp.o
smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o
# Pinmux setup
pfc-y :=
@ -49,6 +51,7 @@ obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o
obj-$(CONFIG_MACH_KOTA2) += board-kota2.o
obj-$(CONFIG_MACH_BONITO) += board-bonito.o
obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o
# Framework support
obj-$(CONFIG_SMP) += $(smp-y)

View File

@ -0,0 +1,85 @@
/*
* kzm9d board support
*
* Copyright (C) 2012 Renesas Solutions Corp.
* Copyright (C) 2012 Magnus Damm
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/smsc911x.h>
#include <mach/common.h>
#include <mach/emev2.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
/* Ether */
static struct resource smsc911x_resources[] = {
[0] = {
.start = 0x20000000,
.end = 0x2000ffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = EMEV2_GPIO_IRQ(1),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
},
};
static struct smsc911x_platform_config smsc911x_platdata = {
.flags = SMSC911X_USE_32BIT,
.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
};
static struct platform_device smsc91x_device = {
.name = "smsc911x",
.id = 0,
.dev = {
.platform_data = &smsc911x_platdata,
},
.num_resources = ARRAY_SIZE(smsc911x_resources),
.resource = smsc911x_resources,
};
static struct platform_device *kzm9d_devices[] __initdata = {
&smsc91x_device,
};
void __init kzm9d_add_standard_devices(void)
{
emev2_add_standard_devices();
platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
}
static const char *kzm9d_boards_compat_dt[] __initdata = {
"renesas,kzm9d",
NULL,
};
DT_MACHINE_START(KZM9D_DT, "kzm9d")
.map_io = emev2_map_io,
.init_early = emev2_add_early_devices,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = emev2_init_irq,
.handle_irq = gic_handle_irq,
.init_machine = kzm9d_add_standard_devices,
.timer = &shmobile_timer,
.dt_compat = kzm9d_boards_compat_dt,
MACHINE_END

View File

@ -0,0 +1,249 @@
/*
* Emma Mobile EV2 clock framework support
*
* Copyright (C) 2012 Magnus Damm
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/sh_clk.h>
#include <linux/clkdev.h>
#include <mach/common.h>
#define EMEV2_SMU_BASE 0xe0110000
/* EMEV2 SMU registers */
#define USIAU0_RSTCTRL 0x094
#define USIBU1_RSTCTRL 0x0ac
#define USIBU2_RSTCTRL 0x0b0
#define USIBU3_RSTCTRL 0x0b4
#define STI_RSTCTRL 0x124
#define USIAU0GCLKCTRL 0x4a0
#define USIBU1GCLKCTRL 0x4b8
#define USIBU2GCLKCTRL 0x4bc
#define USIBU3GCLKCTRL 0x04c0
#define STIGCLKCTRL 0x528
#define USIAU0SCLKDIV 0x61c
#define USIB2SCLKDIV 0x65c
#define USIB3SCLKDIV 0x660
#define STI_CLKSEL 0x688
#define SMU_GENERAL_REG0 0x7c0
/* not pretty, but hey */
static void __iomem *smu_base;
static void emev2_smu_write(unsigned long value, int offs)
{
BUG_ON(!smu_base || (offs >= PAGE_SIZE));
iowrite32(value, smu_base + offs);
}
void emev2_set_boot_vector(unsigned long value)
{
emev2_smu_write(value, SMU_GENERAL_REG0);
}
static struct clk_mapping smu_mapping = {
.phys = EMEV2_SMU_BASE,
.len = PAGE_SIZE,
};
/* Fixed 32 KHz root clock from C32K pin */
static struct clk c32k_clk = {
.rate = 32768,
.mapping = &smu_mapping,
};
/* PLL3 multiplies C32K with 7000 */
static unsigned long pll3_recalc(struct clk *clk)
{
return clk->parent->rate * 7000;
}
static struct sh_clk_ops pll3_clk_ops = {
.recalc = pll3_recalc,
};
static struct clk pll3_clk = {
.ops = &pll3_clk_ops,
.parent = &c32k_clk,
};
static struct clk *main_clks[] = {
&c32k_clk,
&pll3_clk,
};
enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
SCLKDIV_NR };
#define SCLKDIV(_reg, _shift) \
{ \
.parent = &pll3_clk, \
.enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
.enable_bit = _shift, \
}
static struct clk sclkdiv_clks[SCLKDIV_NR] = {
[SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
[SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
[SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
[SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
};
enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
GCLK_STI_SCLK,
GCLK_NR };
#define GCLK_SCLK(_parent, _reg) \
{ \
.parent = _parent, \
.enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
.enable_bit = 1, /* SCLK_GCC */ \
}
static struct clk gclk_clks[GCLK_NR] = {
[GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
USIAU0GCLKCTRL),
[GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
USIBU1GCLKCTRL),
[GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
USIBU2GCLKCTRL),
[GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
USIBU3GCLKCTRL),
[GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
};
static int emev2_gclk_enable(struct clk *clk)
{
iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
clk->mapped_reg);
return 0;
}
static void emev2_gclk_disable(struct clk *clk)
{
iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
clk->mapped_reg);
}
static struct sh_clk_ops emev2_gclk_clk_ops = {
.enable = emev2_gclk_enable,
.disable = emev2_gclk_disable,
.recalc = followparent_recalc,
};
static int __init emev2_gclk_register(struct clk *clks, int nr)
{
struct clk *clkp;
int ret = 0;
int k;
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
clkp->ops = &emev2_gclk_clk_ops;
ret |= clk_register(clkp);
}
return ret;
}
static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
{
unsigned int sclk_div;
sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
return clk->parent->rate / (sclk_div + 1);
}
static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
.recalc = emev2_sclkdiv_recalc,
};
static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
{
struct clk *clkp;
int ret = 0;
int k;
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
clkp->ops = &emev2_sclkdiv_clk_ops;
ret |= clk_register(clkp);
}
return ret;
}
static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
};
void __init emev2_clock_init(void)
{
int k, ret = 0;
static int is_setup;
/* yuck, this is ugly as hell, but the non-smp case of clocks
* code is now designed to rely on ioremap() instead of static
* entity maps. in the case of smp we need access to the SMU
* register earlier than ioremap() is actually working without
* any static maps. to enable SMP in ugly but with dynamic
* mappings we have to call emev2_clock_init() from different
* places depending on UP and SMP...
*/
if (is_setup++)
return;
smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
BUG_ON(!smu_base);
/* setup STI timer to run on 37.768 kHz and deassert reset */
emev2_smu_write(0, STI_CLKSEL);
emev2_smu_write(1, STI_RSTCTRL);
/* deassert reset for UART0->UART3 */
emev2_smu_write(2, USIAU0_RSTCTRL);
emev2_smu_write(2, USIBU1_RSTCTRL);
emev2_smu_write(2, USIBU2_RSTCTRL);
emev2_smu_write(2, USIBU3_RSTCTRL);
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
if (!ret)
ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
if (!ret)
ret = emev2_gclk_register(gclk_clks, GCLK_NR);
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
if (!ret)
shmobile_clk_init();
else
panic("failed to setup emev2 clocks\n");
}

View File

@ -47,6 +47,7 @@
#define PLLC01CR 0xe6150028
#define SUBCKCR 0xe6150080
#define USBCKCR 0xe615008c
#define MSTPSR0 0xe6150030
#define MSTPSR1 0xe6150038
@ -181,6 +182,95 @@ static struct clk pllc1_div2_clk = {
.parent = &pllc1_clk,
};
/* USB clock */
static struct clk *usb24s_parents[] = {
[0] = &system_clk,
[1] = &extal2_clk
};
static int usb24s_enable(struct clk *clk)
{
__raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR);
return 0;
}
static void usb24s_disable(struct clk *clk)
{
__raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR);
}
static int usb24s_set_parent(struct clk *clk, struct clk *parent)
{
int i, ret;
u32 val;
if (!clk->parent_table || !clk->parent_num)
return -EINVAL;
/* Search the parent */
for (i = 0; i < clk->parent_num; i++)
if (clk->parent_table[i] == parent)
break;
if (i == clk->parent_num)
return -ENODEV;
ret = clk_reparent(clk, parent);
if (ret < 0)
return ret;
val = __raw_readl(USBCKCR);
val &= ~(1 << 7);
val |= i << 7;
__raw_writel(val, USBCKCR);
return 0;
}
static struct sh_clk_ops usb24s_clk_ops = {
.recalc = followparent_recalc,
.enable = usb24s_enable,
.disable = usb24s_disable,
.set_parent = usb24s_set_parent,
};
static struct clk usb24s_clk = {
.ops = &usb24s_clk_ops,
.parent_table = usb24s_parents,
.parent_num = ARRAY_SIZE(usb24s_parents),
.parent = &system_clk,
};
static unsigned long usb24_recalc(struct clk *clk)
{
return clk->parent->rate /
((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2);
};
static int usb24_set_rate(struct clk *clk, unsigned long rate)
{
u32 val;
/* closer to which ? parent->rate or parent->rate/2 */
val = __raw_readl(USBCKCR);
val &= ~(1 << 6);
val |= (rate > (clk->parent->rate / 4) * 3) << 6;
__raw_writel(val, USBCKCR);
return 0;
}
static struct sh_clk_ops usb24_clk_ops = {
.recalc = usb24_recalc,
.set_rate = usb24_set_rate,
};
static struct clk usb24_clk = {
.ops = &usb24_clk_ops,
.parent = &usb24s_clk,
};
struct clk *main_clks[] = {
&extalr_clk,
&extal1_clk,
@ -196,6 +286,8 @@ struct clk *main_clks[] = {
&pllc0_clk,
&pllc1_clk,
&pllc1_div2_clk,
&usb24s_clk,
&usb24_clk,
};
static void div4_kick(struct clk *clk)
@ -223,7 +315,7 @@ static struct clk_div4_table div4_table = {
enum {
DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
DIV4_NR
};
@ -234,6 +326,7 @@ struct clk div4_clks[DIV4_NR] = {
[DIV4_M1] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT),
[DIV4_HP] = SH_CLK_DIV4(&pllc1_clk, FRQCRB, 4, 0x6fff, 0),
[DIV4_HPP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0),
[DIV4_USBP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 16, 0x6fff, 0),
[DIV4_S] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0),
[DIV4_ZB] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 8, 0x6fff, 0),
[DIV4_M3] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 4, 0x6fff, 0),
@ -257,7 +350,10 @@ enum {
MSTP222,
MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
MSTP329, MSTP323,
MSTP329, MSTP328, MSTP323, MSTP320,
MSTP314, MSTP313, MSTP312,
MSTP416, MSTP415, MSTP407, MSTP406,
MSTP_NR
};
@ -280,7 +376,17 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
[MSTP329] = SH_CLK_MSTP32(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
[MSTP328] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 28, 0), /* FSI */
[MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 20, 0), /* USBF */
[MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
[MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
[MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
[MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 16, 0), /* USBHOST */
[MSTP415] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
[MSTP407] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-Func */
[MSTP406] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 6, 0), /* USB Phy */
};
static struct clk_lookup lookups[] = {
@ -299,6 +405,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("pllc0_clk", &pllc0_clk),
CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
CLKDEV_CON_ID("usb24s", &usb24s_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
@ -334,7 +441,21 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]),
CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]),
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]),
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]),
CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP320]),
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]),
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]),
CLKDEV_DEV_ID("sh_mmcif", &mstp_clks[MSTP312]),
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]),
/* ICK */
CLKDEV_ICK_ID("host", "renesas_usbhs", &mstp_clks[MSTP416]),
CLKDEV_ICK_ID("func", "renesas_usbhs", &mstp_clks[MSTP407]),
CLKDEV_ICK_ID("phy", "renesas_usbhs", &mstp_clks[MSTP406]),
CLKDEV_ICK_ID("pci", "renesas_usbhs", &div4_clks[DIV4_USBP]),
CLKDEV_ICK_ID("usb24", "renesas_usbhs", &usb24_clk),
};
void __init r8a7740_clock_init(u8 md_ck)

View File

@ -0,0 +1,19 @@
#ifndef __ASM_EMEV2_H__
#define __ASM_EMEV2_H__
extern void emev2_map_io(void);
extern void emev2_init_irq(void);
extern void emev2_add_early_devices(void);
extern void emev2_add_standard_devices(void);
extern void emev2_clock_init(void);
extern void emev2_set_boot_vector(unsigned long value);
extern unsigned int emev2_get_core_count(void);
extern int emev2_platform_cpu_kill(unsigned int cpu);
extern void emev2_secondary_init(unsigned int cpu);
extern int emev2_boot_secondary(unsigned int cpu);
extern void emev2_smp_prepare_cpus(void);
#define EMEV2_GPIO_BASE 200
#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n))
#endif /* __ASM_EMEV2_H__ */

View File

@ -457,6 +457,8 @@ enum {
SHDMA_SLAVE_SDHI1_TX,
SHDMA_SLAVE_SDHI2_RX,
SHDMA_SLAVE_SDHI2_TX,
SHDMA_SLAVE_FSIA_RX,
SHDMA_SLAVE_FSIA_TX,
SHDMA_SLAVE_MMCIF_RX,
SHDMA_SLAVE_MMCIF_TX,
SHDMA_SLAVE_USB0_TX,

View File

@ -515,8 +515,36 @@ enum {
SHDMA_SLAVE_MMCIF_RX,
};
/* PINT interrupts are located at Linux IRQ 800 and up */
#define SH73A0_PINT0_IRQ(irq) ((irq) + 800)
#define SH73A0_PINT1_IRQ(irq) ((irq) + 832)
/*
* SH73A0 IRQ LOCATION TABLE
*
* 416 -----------------------------------------
* IRQ0-IRQ15
* 431 -----------------------------------------
* ...
* 448 -----------------------------------------
* sh73a0-intcs
* sh73a0-intca-irq-pins
* 680 -----------------------------------------
* ...
* 700 -----------------------------------------
* sh73a0-pint0
* 731 -----------------------------------------
* 732 -----------------------------------------
* sh73a0-pint1
* 739 -----------------------------------------
* ...
* 800 -----------------------------------------
* IRQ16-IRQ31
* 815 -----------------------------------------
* ...
* 928 -----------------------------------------
* sh73a0-intca-irq-pins
* 943 -----------------------------------------
*/
/* PINT interrupts are located at Linux IRQ 700 and up */
#define SH73A0_PINT0_IRQ(irq) ((irq) + 700)
#define SH73A0_PINT1_IRQ(irq) ((irq) + 732)
#endif /* __ASM_SH73A0_H__ */

View File

@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <mach/r8a7740.h>
#include <mach/irqs.h>
#define CPU_ALL_PORT(fn, pfx, sfx) \
PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx), \
@ -2527,6 +2528,41 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
{ },
};
static struct pinmux_irq pinmux_irqs[] = {
PINMUX_IRQ(evt2irq(0x0200), PORT2_FN0, PORT13_FN0), /* IRQ0A */
PINMUX_IRQ(evt2irq(0x0220), PORT20_FN0), /* IRQ1A */
PINMUX_IRQ(evt2irq(0x0240), PORT11_FN0, PORT12_FN0), /* IRQ2A */
PINMUX_IRQ(evt2irq(0x0260), PORT10_FN0, PORT14_FN0), /* IRQ3A */
PINMUX_IRQ(evt2irq(0x0280), PORT15_FN0, PORT172_FN0), /* IRQ4A */
PINMUX_IRQ(evt2irq(0x02A0), PORT0_FN0, PORT1_FN0), /* IRQ5A */
PINMUX_IRQ(evt2irq(0x02C0), PORT121_FN0, PORT173_FN0), /* IRQ6A */
PINMUX_IRQ(evt2irq(0x02E0), PORT120_FN0, PORT209_FN0), /* IRQ7A */
PINMUX_IRQ(evt2irq(0x0300), PORT119_FN0), /* IRQ8A */
PINMUX_IRQ(evt2irq(0x0320), PORT118_FN0, PORT210_FN0), /* IRQ9A */
PINMUX_IRQ(evt2irq(0x0340), PORT19_FN0), /* IRQ10A */
PINMUX_IRQ(evt2irq(0x0360), PORT104_FN0), /* IRQ11A */
PINMUX_IRQ(evt2irq(0x0380), PORT42_FN0, PORT97_FN0), /* IRQ12A */
PINMUX_IRQ(evt2irq(0x03A0), PORT64_FN0, PORT98_FN0), /* IRQ13A */
PINMUX_IRQ(evt2irq(0x03C0), PORT63_FN0, PORT99_FN0), /* IRQ14A */
PINMUX_IRQ(evt2irq(0x03E0), PORT62_FN0, PORT100_FN0), /* IRQ15A */
PINMUX_IRQ(evt2irq(0x3200), PORT68_FN0, PORT211_FN0), /* IRQ16A */
PINMUX_IRQ(evt2irq(0x3220), PORT69_FN0), /* IRQ17A */
PINMUX_IRQ(evt2irq(0x3240), PORT70_FN0), /* IRQ18A */
PINMUX_IRQ(evt2irq(0x3260), PORT71_FN0), /* IRQ19A */
PINMUX_IRQ(evt2irq(0x3280), PORT67_FN0), /* IRQ20A */
PINMUX_IRQ(evt2irq(0x32A0), PORT202_FN0), /* IRQ21A */
PINMUX_IRQ(evt2irq(0x32C0), PORT95_FN0), /* IRQ22A */
PINMUX_IRQ(evt2irq(0x32E0), PORT96_FN0), /* IRQ23A */
PINMUX_IRQ(evt2irq(0x3300), PORT180_FN0), /* IRQ24A */
PINMUX_IRQ(evt2irq(0x3320), PORT38_FN0), /* IRQ25A */
PINMUX_IRQ(evt2irq(0x3340), PORT58_FN0, PORT81_FN0), /* IRQ26A */
PINMUX_IRQ(evt2irq(0x3360), PORT57_FN0, PORT168_FN0), /* IRQ27A */
PINMUX_IRQ(evt2irq(0x3380), PORT56_FN0, PORT169_FN0), /* IRQ28A */
PINMUX_IRQ(evt2irq(0x33A0), PORT50_FN0, PORT170_FN0), /* IRQ29A */
PINMUX_IRQ(evt2irq(0x33C0), PORT49_FN0, PORT171_FN0), /* IRQ30A */
PINMUX_IRQ(evt2irq(0x33E0), PORT41_FN0, PORT167_FN0), /* IRQ31A */
};
static struct pinmux_info r8a7740_pinmux_info = {
.name = "r8a7740_pfc",
.reserved_id = PINMUX_RESERVED,
@ -2554,6 +2590,9 @@ static struct pinmux_info r8a7740_pinmux_info = {
.gpio_data = pinmux_data,
.gpio_data_size = ARRAY_SIZE(pinmux_data),
.gpio_irq = pinmux_irqs,
.gpio_irq_size = ARRAY_SIZE(pinmux_irqs),
};
void r8a7740_pinmux_init(void)

View File

@ -16,12 +16,15 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
#include <linux/of.h>
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <mach/common.h>
#include <mach/emev2.h>
#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
#define is_r8a7779() machine_is_marzen()
#define is_emev2() of_machine_is_compatible("renesas,emev2")
static unsigned int __init shmobile_smp_get_core_count(void)
{
@ -31,6 +34,9 @@ static unsigned int __init shmobile_smp_get_core_count(void)
if (is_r8a7779())
return r8a7779_get_core_count();
if (is_emev2())
return emev2_get_core_count();
return 1;
}
@ -41,6 +47,9 @@ static void __init shmobile_smp_prepare_cpus(void)
if (is_r8a7779())
r8a7779_smp_prepare_cpus();
if (is_emev2())
emev2_smp_prepare_cpus();
}
int shmobile_platform_cpu_kill(unsigned int cpu)
@ -48,6 +57,9 @@ int shmobile_platform_cpu_kill(unsigned int cpu)
if (is_r8a7779())
return r8a7779_platform_cpu_kill(cpu);
if (is_emev2())
return emev2_platform_cpu_kill(cpu);
return 1;
}
@ -60,6 +72,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
if (is_r8a7779())
r8a7779_secondary_init(cpu);
if (is_emev2())
emev2_secondary_init(cpu);
}
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@ -70,6 +85,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
if (is_r8a7779())
return r8a7779_boot_secondary(cpu);
if (is_emev2())
return emev2_boot_secondary(cpu);
return -ENOSYS;
}

View File

@ -0,0 +1,452 @@
/*
* Emma Mobile EV2 processor support
*
* Copyright (C) 2012 Magnus Damm
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/platform_data/gpio-em.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/of_irq.h>
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/emev2.h>
#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/hardware/gic.h>
static struct map_desc emev2_io_desc[] __initdata = {
#ifdef CONFIG_SMP
/* 128K entity map for 0xe0100000 (SMU) */
{
.virtual = 0xe0100000,
.pfn = __phys_to_pfn(0xe0100000),
.length = SZ_128K,
.type = MT_DEVICE
},
/* 2M mapping for SCU + L2 controller */
{
.virtual = 0xf0000000,
.pfn = __phys_to_pfn(0x1e000000),
.length = SZ_2M,
.type = MT_DEVICE
},
#endif
};
void __init emev2_map_io(void)
{
iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
}
/* UART */
static struct resource uart0_resources[] = {
[0] = {
.start = 0xe1020000,
.end = 0xe1020037,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 40,
.flags = IORESOURCE_IRQ,
}
};
static struct platform_device uart0_device = {
.name = "serial8250-em",
.id = 0,
.num_resources = ARRAY_SIZE(uart0_resources),
.resource = uart0_resources,
};
static struct resource uart1_resources[] = {
[0] = {
.start = 0xe1030000,
.end = 0xe1030037,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 41,
.flags = IORESOURCE_IRQ,
}
};
static struct platform_device uart1_device = {
.name = "serial8250-em",
.id = 1,
.num_resources = ARRAY_SIZE(uart1_resources),
.resource = uart1_resources,
};
static struct resource uart2_resources[] = {
[0] = {
.start = 0xe1040000,
.end = 0xe1040037,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 42,
.flags = IORESOURCE_IRQ,
}
};
static struct platform_device uart2_device = {
.name = "serial8250-em",
.id = 2,
.num_resources = ARRAY_SIZE(uart2_resources),
.resource = uart2_resources,
};
static struct resource uart3_resources[] = {
[0] = {
.start = 0xe1050000,
.end = 0xe1050037,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 43,
.flags = IORESOURCE_IRQ,
}
};
static struct platform_device uart3_device = {
.name = "serial8250-em",
.id = 3,
.num_resources = ARRAY_SIZE(uart3_resources),
.resource = uart3_resources,
};
/* STI */
static struct resource sti_resources[] = {
[0] = {
.name = "STI",
.start = 0xe0180000,
.end = 0xe0180053,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 157,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sti_device = {
.name = "em_sti",
.id = 0,
.resource = sti_resources,
.num_resources = ARRAY_SIZE(sti_resources),
};
/* GIO */
static struct gpio_em_config gio0_config = {
.gpio_base = 0,
.irq_base = EMEV2_GPIO_IRQ(0),
.number_of_pins = 32,
};
static struct resource gio0_resources[] = {
[0] = {
.name = "GIO_000",
.start = 0xe0050000,
.end = 0xe005002b,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "GIO_000",
.start = 0xe0050040,
.end = 0xe005005f,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 99,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = 100,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device gio0_device = {
.name = "em_gio",
.id = 0,
.resource = gio0_resources,
.num_resources = ARRAY_SIZE(gio0_resources),
.dev = {
.platform_data = &gio0_config,
},
};
static struct gpio_em_config gio1_config = {
.gpio_base = 32,
.irq_base = EMEV2_GPIO_IRQ(32),
.number_of_pins = 32,
};
static struct resource gio1_resources[] = {
[0] = {
.name = "GIO_032",
.start = 0xe0050080,
.end = 0xe00500ab,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "GIO_032",
.start = 0xe00500c0,
.end = 0xe00500df,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 101,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = 102,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device gio1_device = {
.name = "em_gio",
.id = 1,
.resource = gio1_resources,
.num_resources = ARRAY_SIZE(gio1_resources),
.dev = {
.platform_data = &gio1_config,
},
};
static struct gpio_em_config gio2_config = {
.gpio_base = 64,
.irq_base = EMEV2_GPIO_IRQ(64),
.number_of_pins = 32,
};
static struct resource gio2_resources[] = {
[0] = {
.name = "GIO_064",
.start = 0xe0050100,
.end = 0xe005012b,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "GIO_064",
.start = 0xe0050140,
.end = 0xe005015f,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 103,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = 104,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device gio2_device = {
.name = "em_gio",
.id = 2,
.resource = gio2_resources,
.num_resources = ARRAY_SIZE(gio2_resources),
.dev = {
.platform_data = &gio2_config,
},
};
static struct gpio_em_config gio3_config = {
.gpio_base = 96,
.irq_base = EMEV2_GPIO_IRQ(96),
.number_of_pins = 32,
};
static struct resource gio3_resources[] = {
[0] = {
.name = "GIO_096",
.start = 0xe0050100,
.end = 0xe005012b,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "GIO_096",
.start = 0xe0050140,
.end = 0xe005015f,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 105,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = 106,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device gio3_device = {
.name = "em_gio",
.id = 3,
.resource = gio3_resources,
.num_resources = ARRAY_SIZE(gio3_resources),
.dev = {
.platform_data = &gio3_config,
},
};
static struct gpio_em_config gio4_config = {
.gpio_base = 128,
.irq_base = EMEV2_GPIO_IRQ(128),
.number_of_pins = 31,
};
static struct resource gio4_resources[] = {
[0] = {
.name = "GIO_128",
.start = 0xe0050200,
.end = 0xe005022b,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "GIO_128",
.start = 0xe0050240,
.end = 0xe005025f,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 107,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = 108,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device gio4_device = {
.name = "em_gio",
.id = 4,
.resource = gio4_resources,
.num_resources = ARRAY_SIZE(gio4_resources),
.dev = {
.platform_data = &gio4_config,
},
};
static struct platform_device *emev2_early_devices[] __initdata = {
&uart0_device,
&uart1_device,
&uart2_device,
&uart3_device,
};
static struct platform_device *emev2_late_devices[] __initdata = {
&sti_device,
&gio0_device,
&gio1_device,
&gio2_device,
&gio3_device,
&gio4_device,
};
void __init emev2_add_standard_devices(void)
{
emev2_clock_init();
platform_add_devices(emev2_early_devices,
ARRAY_SIZE(emev2_early_devices));
platform_add_devices(emev2_late_devices,
ARRAY_SIZE(emev2_late_devices));
}
void __init emev2_init_delay(void)
{
shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
}
void __init emev2_add_early_devices(void)
{
emev2_init_delay();
early_platform_add_devices(emev2_early_devices,
ARRAY_SIZE(emev2_early_devices));
/* setup early console here as well */
shmobile_setup_console();
}
void __init emev2_init_irq(void)
{
void __iomem *gic_dist_base;
void __iomem *gic_cpu_base;
/* Static mappings, never released */
gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
BUG_ON(!gic_dist_base || !gic_cpu_base);
/* Use GIC to handle interrupts */
gic_init(0, 29, gic_dist_base, gic_cpu_base);
}
#ifdef CONFIG_USE_OF
static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = {
{ }
};
void __init emev2_add_standard_devices_dt(void)
{
of_platform_populate(NULL, of_default_bus_match_table,
emev2_auxdata_lookup, NULL);
}
static const struct of_device_id emev2_dt_irq_match[] = {
{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
{},
};
static const char *emev2_boards_compat_dt[] __initdata = {
"renesas,emev2",
NULL,
};
void __init emev2_init_irq_dt(void)
{
of_irq_init(emev2_dt_irq_match);
}
DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
.init_early = emev2_init_delay,
.nr_irqs = NR_IRQS_LEGACY,
.init_irq = emev2_init_irq_dt,
.handle_irq = gic_handle_irq,
.init_machine = emev2_add_standard_devices_dt,
.timer = &shmobile_timer,
.dt_compat = emev2_boards_compat_dt,
MACHINE_END
#endif /* CONFIG_USE_OF */

View File

@ -350,19 +350,19 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev)
i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
i2c_read(reg, ICSTART); /* dummy read */
mdelay(100);
udelay(10);
i2c_write(reg, ICCR, 0x01);
i2c_read(reg, ICCR);
i2c_write(reg, ICSTART, 0x00);
i2c_read(reg, ICSTART);
udelay(10);
i2c_write(reg, ICCR, 0x10);
mdelay(100);
udelay(10);
i2c_write(reg, ICCR, 0x00);
mdelay(100);
udelay(10);
i2c_write(reg, ICCR, 0x10);
mdelay(100);
udelay(10);
iounmap(reg);
}

View File

@ -461,6 +461,16 @@ static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = {
.addr = 0xe6870030,
.chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
.mid_rid = 0xce,
}, {
.slave_id = SHDMA_SLAVE_FSIA_TX,
.addr = 0xfe1f0024,
.chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
.mid_rid = 0xb1,
}, {
.slave_id = SHDMA_SLAVE_FSIA_RX,
.addr = 0xfe1f0020,
.chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
.mid_rid = 0xb2,
}, {
.slave_id = SHDMA_SLAVE_MMCIF_TX,
.addr = 0xe6bd0034,

View File

@ -0,0 +1,97 @@
/*
* SMP support for Emma Mobile EV2
*
* Copyright (C) 2012 Renesas Solutions Corp.
* Copyright (C) 2012 Magnus Damm
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <mach/common.h>
#include <mach/emev2.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include <asm/hardware/gic.h>
#include <asm/cacheflush.h>
#define EMEV2_SCU_BASE 0x1e000000
static DEFINE_SPINLOCK(scu_lock);
static void __iomem *scu_base;
static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
{
unsigned long tmp;
/* we assume this code is running on a different cpu
* than the one that is changing coherency setting */
spin_lock(&scu_lock);
tmp = readl(scu_base + 8);
tmp &= ~clr;
tmp |= set;
writel(tmp, scu_base + 8);
spin_unlock(&scu_lock);
}
unsigned int __init emev2_get_core_count(void)
{
if (!scu_base) {
scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
emev2_clock_init(); /* need ioremapped SMU */
}
WARN_ON_ONCE(!scu_base);
return scu_base ? scu_get_core_count(scu_base) : 1;
}
int emev2_platform_cpu_kill(unsigned int cpu)
{
return 0; /* not supported yet */
}
void __cpuinit emev2_secondary_init(unsigned int cpu)
{
gic_secondary_init(0);
}
int __cpuinit emev2_boot_secondary(unsigned int cpu)
{
cpu = cpu_logical_map(cpu);
/* enable cache coherency */
modify_scu_cpu_psr(0, 3 << (cpu * 8));
/* Tell ROM loader about our vector (in headsmp.S) */
emev2_set_boot_vector(__pa(shmobile_secondary_vector));
gic_raise_softirq(cpumask_of(cpu), 1);
return 0;
}
void __init emev2_smp_prepare_cpus(void)
{
int cpu = cpu_logical_map(0);
scu_enable(scu_base);
/* enable cache coherency on CPU0 */
modify_scu_cpu_psr(0, 3 << (cpu * 8));
}

View File

@ -36,7 +36,8 @@ void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz,
unsigned int value = (1000000 * mult) / (HZ * div);
lpj_fine = max_cpu_core_mhz * value;
if (!preset_lpj)
preset_lpj = max_cpu_core_mhz * value;
}
static void __init shmobile_late_time_init(void)

View File

@ -102,7 +102,7 @@ static int __init mop500_uib_init(void)
struct i2c_adapter *i2c0;
int ret;
if (!cpu_is_u8500())
if (!cpu_is_u8500_family())
return -ENODEV;
if (uib) {

View File

@ -36,7 +36,9 @@ static int __init ux500_l2x0_unlock(void)
static int __init ux500_l2x0_init(void)
{
if (cpu_is_u8500())
u32 aux_val = 0x3e000000;
if (cpu_is_u8500_family())
l2x0_base = __io_address(U8500_L2CC_BASE);
else
ux500_unknown_soc();
@ -44,11 +46,19 @@ static int __init ux500_l2x0_init(void)
/* Unlock before init */
ux500_l2x0_unlock();
/* DB9540's L2 has 128KB way size */
if (cpu_is_u9540())
/* 128KB way size */
aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
else
/* 64KB way size */
aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
/* 64KB way size, 8 way associativity, force WA */
if (of_have_populated_dt())
l2x0_of_init(0x3e060000, 0xc0000fff);
l2x0_of_init(aux_val, 0xc0000fff);
else
l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
l2x0_init(l2x0_base, aux_val, 0xc0000fff);
/*
* We can't disable l2 as we are in non secure mode, currently

View File

@ -149,7 +149,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
unsigned long mturate;
unsigned long retclk;
if (cpu_is_u8500())
if (cpu_is_u8500_family())
addr = __io_address(U8500_PRCMU_BASE);
else
ux500_unknown_soc();

View File

@ -34,8 +34,8 @@ static struct map_desc u8500_uart_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_UART0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_UART2_BASE, SZ_4K),
};
static struct map_desc u8500_io_desc[] __initdata = {
/* U8500 and U9540 common io_desc */
static struct map_desc u8500_common_io_desc[] __initdata = {
/* SCU base also covers GIC CPU BASE and TWD with its 4K page */
__IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
@ -49,12 +49,23 @@ static struct map_desc u8500_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K),
__IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K),
__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
};
/* U8500 IO map specific description */
static struct map_desc u8500_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
};
/* U9540 IO map specific description */
static struct map_desc u9540_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K + SZ_8K),
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K + SZ_8K),
};
void __init u8500_map_io(void)
@ -66,7 +77,12 @@ void __init u8500_map_io(void)
ux500_map_io();
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
if (cpu_is_u9540())
iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
else
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
_PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
}

View File

@ -39,7 +39,7 @@ void __init ux500_init_irq(void)
void __iomem *dist_base;
void __iomem *cpu_base;
if (cpu_is_u8500()) {
if (cpu_is_u8500_family()) {
dist_base = __io_address(U8500_GIC_DIST_BASE);
cpu_base = __io_address(U8500_GIC_CPU_BASE);
} else
@ -56,7 +56,7 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
if (cpu_is_u8500())
if (cpu_is_u8500_family())
db8500_prcmu_early_init();
clk_init();
}

View File

@ -23,7 +23,7 @@ static unsigned int ux500_read_asicid(phys_addr_t addr)
{
phys_addr_t base = addr & ~0xfff;
struct map_desc desc = {
.virtual = IO_ADDRESS(base),
.virtual = UX500_VIRT_ROM,
.pfn = __phys_to_pfn(base),
.length = SZ_16K,
.type = MT_DEVICE,
@ -35,7 +35,7 @@ static unsigned int ux500_read_asicid(phys_addr_t addr)
local_flush_tlb_all();
flush_cache_all();
return readl(__io_address(addr));
return readl(IOMEM(UX500_VIRT_ROM + (addr & 0xfff)));
}
static void ux500_print_soc_info(unsigned int asicid)
@ -67,6 +67,7 @@ static unsigned int partnumber(unsigned int asicid)
* DB8500v2 0x412fc091 0x9001DBF4 0x008500B0
* DB8520v2.2 0x412fc091 0x9001DBF4 0x008500B2
* DB5500v1 0x412fc091 0x9001FFF4 0x005500A0
* DB9540 0x413fc090 0xFFFFDBF4 0x009540xx
*/
void __init ux500_map_io(void)
@ -91,6 +92,10 @@ void __init ux500_map_io(void)
/* DB5500v1 */
addr = 0x9001FFF4;
break;
case 0x413fc090: /* DB9540 */
addr = 0xFFFFDBF4;
break;
}
if (addr)

View File

@ -41,6 +41,10 @@
/* ASIC ID is at 0xbf4 offset within this region */
#define U8500_ASIC_ID_BASE 0x9001D000
#define U9540_BOOT_ROM_BASE 0xFFFE0000
/* ASIC ID is at 0xbf4 offset within this region */
#define U9540_ASIC_ID_BASE 0xFFFFD000
#define U8500_PER6_BASE 0xa03c0000
#define U8500_PER7_BASE 0xa03d0000
#define U8500_PER5_BASE 0xa03e0000
@ -96,7 +100,9 @@
#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
#define U9540_DMC1_BASE (U8500_PER4_BASE + 0x0A000)
#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
#define U9540_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x6A000)
#define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000)
#define U8500_PRCMU_TIMER_3_BASE (U8500_PER4_BASE + 0x07338)
#define U8500_PRCMU_TIMER_4_BASE (U8500_PER4_BASE + 0x07450)

View File

@ -17,6 +17,8 @@
*/
#define U8500_IO_VIRTUAL 0xf0000000
#define U8500_IO_PHYSICAL 0xa0000000
/* This is where we map in the ROM to check ASIC IDs */
#define UX500_VIRT_ROM 0xf0000000
/* This macro is used in assembly, so no cast */
#define IO_ADDRESS(x) \
@ -24,6 +26,7 @@
/* typesafe io address */
#define __io_address(n) IOMEM(IO_ADDRESS(n))
/* Used by some plat-nomadik code */
#define io_p2v(n) __io_address(n)

View File

@ -41,6 +41,16 @@ static inline bool __attribute_const__ cpu_is_u8500(void)
return dbx500_partnumber() == 0x8500;
}
static inline bool __attribute_const__ cpu_is_u9540(void)
{
return dbx500_partnumber() == 0x9540;
}
static inline bool cpu_is_u8500_family(void)
{
return cpu_is_u8500() || cpu_is_u9540();
}
static inline bool __attribute_const__ cpu_is_u5500(void)
{
return dbx500_partnumber() == 0x5500;
@ -111,7 +121,12 @@ static inline bool cpu_is_u8500v21(void)
static inline bool cpu_is_u8500v20_or_later(void)
{
return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
/*
* U9540 has so much in common with U8500 that is is considered a
* U8500 variant.
*/
return cpu_is_u9540() ||
(cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
}
static inline bool ux500_is_svp(void)

View File

@ -24,7 +24,7 @@
*/
#define IRQ_MTU0 (IRQ_SHPI_START + 4)
#define DBX500_NR_INTERNAL_IRQS 160
#define DBX500_NR_INTERNAL_IRQS 166
/* After chip-specific IRQ numbers we have the GPIO ones */
#define NOMADIK_NR_GPIO 288

View File

@ -48,7 +48,7 @@ static void write_pen_release(int val)
static void __iomem *scu_base_addr(void)
{
if (cpu_is_u8500())
if (cpu_is_u8500_family())
return __io_address(U8500_SCU_BASE);
else
ux500_unknown_soc();
@ -118,7 +118,7 @@ static void __init wakeup_secondary(void)
{
void __iomem *backupram;
if (cpu_is_u8500())
if (cpu_is_u8500_family())
backupram = __io_address(U8500_BACKUPRAM0_BASE);
else
ux500_unknown_soc();

View File

@ -54,7 +54,7 @@ static void __init ux500_timer_init(void)
void __iomem *tmp_base;
struct device_node *np;
if (cpu_is_u8500()) {
if (cpu_is_u8500_family()) {
mtu_timer_base = __io_address(U8500_MTU0_BASE);
prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
} else {

View File

@ -161,7 +161,7 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
static int __init db8500_cpufreq_register(void)
{
if (!cpu_is_u8500v20_or_later())
if (!cpu_is_u8500_family())
return -ENODEV;
pr_info("cpufreq for DB8500 started\n");

View File

@ -91,6 +91,12 @@ config GPIO_IT8761E
help
Say yes here to support GPIO functionality of IT8761E super I/O chip.
config GPIO_EM
tristate "Emma Mobile GPIO"
depends on ARM
help
Say yes here to support GPIO on Renesas Emma Mobile SoCs.
config GPIO_EP93XX
def_bool y
depends on ARCH_EP93XX

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o

418
drivers/gpio/gpio-em.c Normal file
View File

@ -0,0 +1,418 @@
/*
* Emma Mobile GPIO Support - GIO
*
* Copyright (C) 2012 Magnus Damm
*
* 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
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_data/gpio-em.h>
struct em_gio_priv {
void __iomem *base0;
void __iomem *base1;
unsigned int irq_base;
spinlock_t sense_lock;
struct platform_device *pdev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
struct irq_domain *irq_domain;
};
#define GIO_E1 0x00
#define GIO_E0 0x04
#define GIO_EM 0x04
#define GIO_OL 0x08
#define GIO_OH 0x0c
#define GIO_I 0x10
#define GIO_IIA 0x14
#define GIO_IEN 0x18
#define GIO_IDS 0x1c
#define GIO_IIM 0x1c
#define GIO_RAW 0x20
#define GIO_MST 0x24
#define GIO_IIR 0x28
#define GIO_IDT0 0x40
#define GIO_IDT1 0x44
#define GIO_IDT2 0x48
#define GIO_IDT3 0x4c
#define GIO_RAWBL 0x50
#define GIO_RAWBH 0x54
#define GIO_IRBL 0x58
#define GIO_IRBH 0x5c
#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
{
if (offs < GIO_IDT0)
return ioread32(p->base0 + offs);
else
return ioread32(p->base1 + (offs - GIO_IDT0));
}
static inline void em_gio_write(struct em_gio_priv *p, int offs,
unsigned long value)
{
if (offs < GIO_IDT0)
iowrite32(value, p->base0 + offs);
else
iowrite32(value, p->base1 + (offs - GIO_IDT0));
}
static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
{
struct irq_chip *chip = irq_data_get_irq_chip(d);
return container_of(chip, struct em_gio_priv, irq_chip);
}
static void em_gio_irq_disable(struct irq_data *d)
{
struct em_gio_priv *p = irq_to_priv(d);
em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
}
static void em_gio_irq_enable(struct irq_data *d)
{
struct em_gio_priv *p = irq_to_priv(d);
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
}
#define GIO_ASYNC(x) (x + 8)
static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
[IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
[IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
[IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
[IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
[IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
};
static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
{
unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
struct em_gio_priv *p = irq_to_priv(d);
unsigned int reg, offset, shift;
unsigned long flags;
unsigned long tmp;
if (!value)
return -EINVAL;
offset = irqd_to_hwirq(d);
pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
/* 8 x 4 bit fields in 4 IDT registers */
reg = GIO_IDT(offset >> 3);
shift = (offset & 0x07) << 4;
spin_lock_irqsave(&p->sense_lock, flags);
/* disable the interrupt in IIA */
tmp = em_gio_read(p, GIO_IIA);
tmp &= ~BIT(offset);
em_gio_write(p, GIO_IIA, tmp);
/* change the sense setting in IDT */
tmp = em_gio_read(p, reg);
tmp &= ~(0xf << shift);
tmp |= value << shift;
em_gio_write(p, reg, tmp);
/* clear pending interrupts */
em_gio_write(p, GIO_IIR, BIT(offset));
/* enable the interrupt in IIA */
tmp = em_gio_read(p, GIO_IIA);
tmp |= BIT(offset);
em_gio_write(p, GIO_IIA, tmp);
spin_unlock_irqrestore(&p->sense_lock, flags);
return 0;
}
static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
{
struct em_gio_priv *p = dev_id;
unsigned long pending;
unsigned int offset, irqs_handled = 0;
while ((pending = em_gio_read(p, GIO_MST))) {
offset = __ffs(pending);
em_gio_write(p, GIO_IIR, BIT(offset));
generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
irqs_handled++;
}
return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
}
static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
{
return container_of(chip, struct em_gio_priv, gpio_chip);
}
static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
{
em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
return 0;
}
static int em_gio_get(struct gpio_chip *chip, unsigned offset)
{
return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
}
static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
unsigned shift, int value)
{
/* upper 16 bits contains mask and lower 16 actual value */
em_gio_write(gpio_to_priv(chip), reg,
(1 << (shift + 16)) | (value << shift));
}
static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
{
/* output is split into two registers */
if (offset < 16)
__em_gio_set(chip, GIO_OL, offset, value);
else
__em_gio_set(chip, GIO_OH, offset - 16, value);
}
static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
/* write GPIO value to output before selecting output mode of pin */
em_gio_set(chip, offset, value);
em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
return 0;
}
static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
{
return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
}
static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct em_gio_priv *p = h->host_data;
pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
irq_set_chip_data(virq, h->host_data);
irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
set_irq_flags(virq, IRQF_VALID); /* kill me now */
return 0;
}
static struct irq_domain_ops em_gio_irq_domain_ops = {
.map = em_gio_irq_domain_map,
};
static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
{
struct platform_device *pdev = p->pdev;
struct gpio_em_config *pdata = pdev->dev.platform_data;
p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
pdata->number_of_pins, numa_node_id());
if (IS_ERR_VALUE(p->irq_base)) {
dev_err(&pdev->dev, "cannot get irq_desc\n");
return -ENXIO;
}
pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
pdata->gpio_base, pdata->number_of_pins, p->irq_base);
p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
pdata->number_of_pins,
p->irq_base, 0,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain) {
irq_free_descs(p->irq_base, pdata->number_of_pins);
return -ENXIO;
}
return 0;
}
static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
{
struct gpio_em_config *pdata = p->pdev->dev.platform_data;
irq_free_descs(p->irq_base, pdata->number_of_pins);
/* FIXME: irq domain wants to be freed! */
}
static int __devinit em_gio_probe(struct platform_device *pdev)
{
struct gpio_em_config *pdata = pdev->dev.platform_data;
struct em_gio_priv *p;
struct resource *io[2], *irq[2];
struct gpio_chip *gpio_chip;
struct irq_chip *irq_chip;
const char *name = dev_name(&pdev->dev);
int ret;
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
ret = -ENOMEM;
goto err0;
}
p->pdev = pdev;
platform_set_drvdata(pdev, p);
spin_lock_init(&p->sense_lock);
io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
ret = -EINVAL;
goto err1;
}
p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
if (!p->base0) {
dev_err(&pdev->dev, "failed to remap low I/O memory\n");
ret = -ENXIO;
goto err1;
}
p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
if (!p->base1) {
dev_err(&pdev->dev, "failed to remap high I/O memory\n");
ret = -ENXIO;
goto err2;
}
gpio_chip = &p->gpio_chip;
gpio_chip->direction_input = em_gio_direction_input;
gpio_chip->get = em_gio_get;
gpio_chip->direction_output = em_gio_direction_output;
gpio_chip->set = em_gio_set;
gpio_chip->to_irq = em_gio_to_irq;
gpio_chip->label = name;
gpio_chip->owner = THIS_MODULE;
gpio_chip->base = pdata->gpio_base;
gpio_chip->ngpio = pdata->number_of_pins;
irq_chip = &p->irq_chip;
irq_chip->name = name;
irq_chip->irq_mask = em_gio_irq_disable;
irq_chip->irq_unmask = em_gio_irq_enable;
irq_chip->irq_enable = em_gio_irq_enable;
irq_chip->irq_disable = em_gio_irq_disable;
irq_chip->irq_set_type = em_gio_irq_set_type;
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
ret = em_gio_irq_domain_init(p);
if (ret) {
dev_err(&pdev->dev, "cannot initialize irq domain\n");
goto err3;
}
if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request low IRQ\n");
ret = -ENOENT;
goto err4;
}
if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request high IRQ\n");
ret = -ENOENT;
goto err5;
}
ret = gpiochip_add(gpio_chip);
if (ret) {
dev_err(&pdev->dev, "failed to add GPIO controller\n");
goto err6;
}
return 0;
err6:
free_irq(irq[1]->start, pdev);
err5:
free_irq(irq[0]->start, pdev);
err4:
em_gio_irq_domain_cleanup(p);
err3:
iounmap(p->base1);
err2:
iounmap(p->base0);
err1:
kfree(p);
err0:
return ret;
}
static int __devexit em_gio_remove(struct platform_device *pdev)
{
struct em_gio_priv *p = platform_get_drvdata(pdev);
struct resource *irq[2];
int ret;
ret = gpiochip_remove(&p->gpio_chip);
if (ret)
return ret;
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
free_irq(irq[1]->start, pdev);
free_irq(irq[0]->start, pdev);
em_gio_irq_domain_cleanup(p);
iounmap(p->base1);
iounmap(p->base0);
kfree(p);
return 0;
}
static struct platform_driver em_gio_device_driver = {
.probe = em_gio_probe,
.remove = __devexit_p(em_gio_remove),
.driver = {
.name = "em_gio",
}
};
module_platform_driver(em_gio_device_driver);
MODULE_AUTHOR("Magnus Damm");
MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,10 @@
#ifndef __GPIO_EM_H__
#define __GPIO_EM_H__
struct gpio_em_config {
unsigned int gpio_base;
unsigned int irq_base;
unsigned int number_of_pins;
};
#endif /* __GPIO_EM_H__ */