diff options
Diffstat (limited to 'arch/arm/plat-orion')
| -rw-r--r-- | arch/arm/plat-orion/Makefile | 10 | ||||
| -rw-r--r-- | arch/arm/plat-orion/common.c | 884 | ||||
| -rw-r--r-- | arch/arm/plat-orion/gpio.c | 671 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/addr-map.h | 54 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/cache-feroceon-l2.h | 11 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/common.h | 113 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/ehci-orion.h | 27 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/gpio.h | 38 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/irq.h | 2 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/mpp.h | 34 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/mv_xor.h | 30 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/orion-gpio.h | 36 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/orion_nand.h | 25 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/pcie.h | 6 | ||||
| -rw-r--r-- | arch/arm/plat-orion/include/plat/time.h | 5 | ||||
| -rw-r--r-- | arch/arm/plat-orion/irq.c | 55 | ||||
| -rw-r--r-- | arch/arm/plat-orion/mpp.c | 78 | ||||
| -rw-r--r-- | arch/arm/plat-orion/pcie.c | 53 | ||||
| -rw-r--r-- | arch/arm/plat-orion/time.c | 147 |
19 files changed, 1795 insertions, 484 deletions
diff --git a/arch/arm/plat-orion/Makefile b/arch/arm/plat-orion/Makefile index 56021a72e10..9433605cd29 100644 --- a/arch/arm/plat-orion/Makefile +++ b/arch/arm/plat-orion/Makefile @@ -1,10 +1,8 @@ # # Makefile for the linux kernel. # +ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include -obj-y := irq.o pcie.o time.o -obj-m := -obj-n := -obj- := - -obj-$(CONFIG_GENERIC_GPIO) += gpio.o +orion-gpio-$(CONFIG_GPIOLIB) += gpio.o +obj-$(CONFIG_PLAT_ORION_LEGACY) += irq.o pcie.o time.o common.o mpp.o +obj-$(CONFIG_PLAT_ORION_LEGACY) += $(orion-gpio-y) diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c new file mode 100644 index 00000000000..3ec6e8e8d36 --- /dev/null +++ b/arch/arm/plat-orion/common.c @@ -0,0 +1,884 @@ +/* + * arch/arm/plat-orion/common.c + * + * Marvell Orion SoC common setup code used by multiple mach-/common.c + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/serial_8250.h> +#include <linux/ata_platform.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/mv643xx_eth.h> +#include <linux/mv643xx_i2c.h> +#include <net/dsa.h> +#include <linux/platform_data/dma-mv_xor.h> +#include <linux/platform_data/usb-ehci-orion.h> +#include <mach/bridge-regs.h> +#include <plat/common.h> + +/* Create a clkdev entry for a given device/clk */ +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk) +{ + struct clk_lookup *cl; + + cl = clkdev_alloc(clk, con_id, dev_id); + if (cl) + clkdev_add(cl); +} + +/* Create clkdev entries for all orion platforms except kirkwood. + Kirkwood has gated clocks for some of its peripherals, so creates + its own clkdev entries. For all the other orion devices, create + clkdev entries to the tclk. */ +void __init orion_clkdev_init(struct clk *tclk) +{ + orion_clkdev_add(NULL, "orion_spi.0", tclk); + orion_clkdev_add(NULL, "orion_spi.1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".2", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".3", tclk); + orion_clkdev_add(NULL, "orion_wdt", tclk); + orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".0", tclk); +} + +/* Fill in the resources structure and link it into the platform + device structure. There is always a memory region, and nearly + always an interrupt.*/ +static void fill_resources(struct platform_device *device, + struct resource *resources, + resource_size_t mapbase, + resource_size_t size, + unsigned int irq) +{ + device->resource = resources; + device->num_resources = 1; + resources[0].flags = IORESOURCE_MEM; + resources[0].start = mapbase; + resources[0].end = mapbase + size; + + if (irq != NO_IRQ) { + device->num_resources++; + resources[1].flags = IORESOURCE_IRQ; + resources[1].start = irq; + resources[1].end = irq; + } +} + +/***************************************************************************** + * UART + ****************************************************************************/ +static unsigned long __init uart_get_clk_rate(struct clk *clk) +{ + clk_prepare_enable(clk); + return clk_get_rate(clk); +} + +static void __init uart_complete( + struct platform_device *orion_uart, + struct plat_serial8250_port *data, + struct resource *resources, + void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk) +{ + data->mapbase = mapbase; + data->membase = membase; + data->irq = irq; + data->uartclk = uart_get_clk_rate(clk); + orion_uart->dev.platform_data = data; + + fill_resources(orion_uart, resources, mapbase, 0xff, irq); + platform_device_register(orion_uart); +} + +/***************************************************************************** + * UART0 + ****************************************************************************/ +static struct plat_serial8250_port orion_uart0_data[] = { + { + .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + }, { + }, +}; + +static struct resource orion_uart0_resources[2]; + +static struct platform_device orion_uart0 = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, +}; + +void __init orion_uart0_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk) +{ + uart_complete(&orion_uart0, orion_uart0_data, orion_uart0_resources, + membase, mapbase, irq, clk); +} + +/***************************************************************************** + * UART1 + ****************************************************************************/ +static struct plat_serial8250_port orion_uart1_data[] = { + { + .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + }, { + }, +}; + +static struct resource orion_uart1_resources[2]; + +static struct platform_device orion_uart1 = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM1, +}; + +void __init orion_uart1_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk) +{ + uart_complete(&orion_uart1, orion_uart1_data, orion_uart1_resources, + membase, mapbase, irq, clk); +} + +/***************************************************************************** + * UART2 + ****************************************************************************/ +static struct plat_serial8250_port orion_uart2_data[] = { + { + .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + }, { + }, +}; + +static struct resource orion_uart2_resources[2]; + +static struct platform_device orion_uart2 = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM2, +}; + +void __init orion_uart2_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk) +{ + uart_complete(&orion_uart2, orion_uart2_data, orion_uart2_resources, + membase, mapbase, irq, clk); +} + +/***************************************************************************** + * UART3 + ****************************************************************************/ +static struct plat_serial8250_port orion_uart3_data[] = { + { + .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + }, { + }, +}; + +static struct resource orion_uart3_resources[2]; + +static struct platform_device orion_uart3 = { + .name = "serial8250", + .id = 3, +}; + +void __init orion_uart3_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk) +{ + uart_complete(&orion_uart3, orion_uart3_data, orion_uart3_resources, + membase, mapbase, irq, clk); +} + +/***************************************************************************** + * SoC RTC + ****************************************************************************/ +static struct resource orion_rtc_resource[2]; + +void __init orion_rtc_init(unsigned long mapbase, + unsigned long irq) +{ + orion_rtc_resource[0].start = mapbase; + orion_rtc_resource[0].end = mapbase + SZ_32 - 1; + orion_rtc_resource[0].flags = IORESOURCE_MEM; + orion_rtc_resource[1].start = irq; + orion_rtc_resource[1].end = irq; + orion_rtc_resource[1].flags = IORESOURCE_IRQ; + + platform_device_register_simple("rtc-mv", -1, orion_rtc_resource, 2); +} + +/***************************************************************************** + * GE + ****************************************************************************/ +static __init void ge_complete( + struct mv643xx_eth_shared_platform_data *orion_ge_shared_data, + struct resource *orion_ge_resource, unsigned long irq, + struct platform_device *orion_ge_shared, + struct platform_device *orion_ge_mvmdio, + struct mv643xx_eth_platform_data *eth_data, + struct platform_device *orion_ge) +{ + orion_ge_resource->start = irq; + orion_ge_resource->end = irq; + eth_data->shared = orion_ge_shared; + orion_ge->dev.platform_data = eth_data; + + platform_device_register(orion_ge_shared); + if (orion_ge_mvmdio) + platform_device_register(orion_ge_mvmdio); + platform_device_register(orion_ge); +} + +/***************************************************************************** + * GE00 + ****************************************************************************/ +static struct mv643xx_eth_shared_platform_data orion_ge00_shared_data; + +static struct resource orion_ge00_shared_resources[] = { + { + .name = "ge00 base", + }, +}; + +static struct platform_device orion_ge00_shared = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 0, + .dev = { + .platform_data = &orion_ge00_shared_data, + }, +}; + +static struct resource orion_ge_mvmdio_resources[] = { + { + .name = "ge00 mvmdio base", + }, { + .name = "ge00 mvmdio err irq", + }, +}; + +static struct platform_device orion_ge_mvmdio = { + .name = "orion-mdio", + .id = -1, +}; + +static struct resource orion_ge00_resources[] = { + { + .name = "ge00 irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device orion_ge00 = { + .name = MV643XX_ETH_NAME, + .id = 0, + .num_resources = 1, + .resource = orion_ge00_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err, + unsigned int tx_csum_limit) +{ + fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); + fill_resources(&orion_ge_mvmdio, orion_ge_mvmdio_resources, + mapbase + 0x2004, 0x84 - 1, irq_err); + orion_ge00_shared_data.tx_csum_limit = tx_csum_limit; + ge_complete(&orion_ge00_shared_data, + orion_ge00_resources, irq, &orion_ge00_shared, + &orion_ge_mvmdio, + eth_data, &orion_ge00); +} + +/***************************************************************************** + * GE01 + ****************************************************************************/ +static struct mv643xx_eth_shared_platform_data orion_ge01_shared_data; + +static struct resource orion_ge01_shared_resources[] = { + { + .name = "ge01 base", + } +}; + +static struct platform_device orion_ge01_shared = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 1, + .dev = { + .platform_data = &orion_ge01_shared_data, + }, +}; + +static struct resource orion_ge01_resources[] = { + { + .name = "ge01 irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device orion_ge01 = { + .name = MV643XX_ETH_NAME, + .id = 1, + .num_resources = 1, + .resource = orion_ge01_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err, + unsigned int tx_csum_limit) +{ + fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); + orion_ge01_shared_data.tx_csum_limit = tx_csum_limit; + ge_complete(&orion_ge01_shared_data, + orion_ge01_resources, irq, &orion_ge01_shared, + NULL, + eth_data, &orion_ge01); +} + +/***************************************************************************** + * GE10 + ****************************************************************************/ +static struct mv643xx_eth_shared_platform_data orion_ge10_shared_data; + +static struct resource orion_ge10_shared_resources[] = { + { + .name = "ge10 base", + } +}; + +static struct platform_device orion_ge10_shared = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 2, + .dev = { + .platform_data = &orion_ge10_shared_data, + }, +}; + +static struct resource orion_ge10_resources[] = { + { + .name = "ge10 irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device orion_ge10 = { + .name = MV643XX_ETH_NAME, + .id = 2, + .num_resources = 1, + .resource = orion_ge10_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err) +{ + fill_resources(&orion_ge10_shared, orion_ge10_shared_resources, + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); + ge_complete(&orion_ge10_shared_data, + orion_ge10_resources, irq, &orion_ge10_shared, + NULL, + eth_data, &orion_ge10); +} + +/***************************************************************************** + * GE11 + ****************************************************************************/ +static struct mv643xx_eth_shared_platform_data orion_ge11_shared_data; + +static struct resource orion_ge11_shared_resources[] = { + { + .name = "ge11 base", + }, +}; + +static struct platform_device orion_ge11_shared = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 3, + .dev = { + .platform_data = &orion_ge11_shared_data, + }, +}; + +static struct resource orion_ge11_resources[] = { + { + .name = "ge11 irq", + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device orion_ge11 = { + .name = MV643XX_ETH_NAME, + .id = 3, + .num_resources = 1, + .resource = orion_ge11_resources, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err) +{ + fill_resources(&orion_ge11_shared, orion_ge11_shared_resources, + mapbase + 0x2000, SZ_16K - 1, NO_IRQ); + ge_complete(&orion_ge11_shared_data, + orion_ge11_resources, irq, &orion_ge11_shared, + NULL, + eth_data, &orion_ge11); +} + +/***************************************************************************** + * Ethernet switch + ****************************************************************************/ +static struct resource orion_switch_resources[] = { + { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device orion_switch_device = { + .name = "dsa", + .id = 0, + .num_resources = 0, + .resource = orion_switch_resources, +}; + +void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq) +{ + int i; + + if (irq != NO_IRQ) { + orion_switch_resources[0].start = irq; + orion_switch_resources[0].end = irq; + orion_switch_device.num_resources = 1; + } + + d->netdev = &orion_ge00.dev; + for (i = 0; i < d->nr_chips; i++) + d->chip[i].mii_bus = &orion_ge00_shared.dev; + orion_switch_device.dev.platform_data = d; + + platform_device_register(&orion_switch_device); +} + +/***************************************************************************** + * I2C + ****************************************************************************/ +static struct mv64xxx_i2c_pdata orion_i2c_pdata = { + .freq_n = 3, + .timeout = 1000, /* Default timeout of 1 second */ +}; + +static struct resource orion_i2c_resources[2]; + +static struct platform_device orion_i2c = { + .name = MV64XXX_I2C_CTLR_NAME, + .id = 0, + .dev = { + .platform_data = &orion_i2c_pdata, + }, +}; + +static struct mv64xxx_i2c_pdata orion_i2c_1_pdata = { + .freq_n = 3, + .timeout = 1000, /* Default timeout of 1 second */ +}; + +static struct resource orion_i2c_1_resources[2]; + +static struct platform_device orion_i2c_1 = { + .name = MV64XXX_I2C_CTLR_NAME, + .id = 1, + .dev = { + .platform_data = &orion_i2c_1_pdata, + }, +}; + +void __init orion_i2c_init(unsigned long mapbase, + unsigned long irq, + unsigned long freq_m) +{ + orion_i2c_pdata.freq_m = freq_m; + fill_resources(&orion_i2c, orion_i2c_resources, mapbase, + SZ_32 - 1, irq); + platform_device_register(&orion_i2c); +} + +void __init orion_i2c_1_init(unsigned long mapbase, + unsigned long irq, + unsigned long freq_m) +{ + orion_i2c_1_pdata.freq_m = freq_m; + fill_resources(&orion_i2c_1, orion_i2c_1_resources, mapbase, + SZ_32 - 1, irq); + platform_device_register(&orion_i2c_1); +} + +/***************************************************************************** + * SPI + ****************************************************************************/ +static struct resource orion_spi_resources; + +static struct platform_device orion_spi = { + .name = "orion_spi", + .id = 0, +}; + +static struct resource orion_spi_1_resources; + +static struct platform_device orion_spi_1 = { + .name = "orion_spi", + .id = 1, +}; + +/* Note: The SPI silicon core does have interrupts. However the + * current Linux software driver does not use interrupts. */ + +void __init orion_spi_init(unsigned long mapbase) +{ + fill_resources(&orion_spi, &orion_spi_resources, + mapbase, SZ_512 - 1, NO_IRQ); + platform_device_register(&orion_spi); +} + +void __init orion_spi_1_init(unsigned long mapbase) +{ + fill_resources(&orion_spi_1, &orion_spi_1_resources, + mapbase, SZ_512 - 1, NO_IRQ); + platform_device_register(&orion_spi_1); +} + +/***************************************************************************** + * Watchdog + ****************************************************************************/ +static struct resource orion_wdt_resource[] = { + DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04), + DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04), +}; + +static struct platform_device orion_wdt_device = { + .name = "orion_wdt", + .id = -1, + .num_resources = ARRAY_SIZE(orion_wdt_resource), + .resource = orion_wdt_resource, +}; + +void __init orion_wdt_init(void) +{ + platform_device_register(&orion_wdt_device); +} + +/***************************************************************************** + * XOR + ****************************************************************************/ +static u64 orion_xor_dmamask = DMA_BIT_MASK(32); + +/***************************************************************************** + * XOR0 + ****************************************************************************/ +static struct resource orion_xor0_shared_resources[] = { + { + .name = "xor 0 low", + .flags = IORESOURCE_MEM, + }, { + .name = "xor 0 high", + .flags = IORESOURCE_MEM, + }, { + .name = "irq channel 0", + .flags = IORESOURCE_IRQ, + }, { + .name = "irq channel 1", + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mv_xor_channel_data orion_xor0_channels_data[2]; + +static struct mv_xor_platform_data orion_xor0_pdata = { + .channels = orion_xor0_channels_data, +}; + +static struct platform_device orion_xor0_shared = { + .name = MV_XOR_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(orion_xor0_shared_resources), + .resource = orion_xor0_shared_resources, + .dev = { + .dma_mask = &orion_xor_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(64), + .platform_data = &orion_xor0_pdata, + }, +}; + +void __init orion_xor0_init(unsigned long mapbase_low, + unsigned long mapbase_high, + unsigned long irq_0, + unsigned long irq_1) +{ + orion_xor0_shared_resources[0].start = mapbase_low; + orion_xor0_shared_resources[0].end = mapbase_low + 0xff; + orion_xor0_shared_resources[1].start = mapbase_high; + orion_xor0_shared_resources[1].end = mapbase_high + 0xff; + + orion_xor0_shared_resources[2].start = irq_0; + orion_xor0_shared_resources[2].end = irq_0; + orion_xor0_shared_resources[3].start = irq_1; + orion_xor0_shared_resources[3].end = irq_1; + + dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[0].cap_mask); + dma_cap_set(DMA_XOR, orion_xor0_channels_data[0].cap_mask); + + dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[1].cap_mask); + dma_cap_set(DMA_XOR, orion_xor0_channels_data[1].cap_mask); + + platform_device_register(&orion_xor0_shared); +} + +/***************************************************************************** + * XOR1 + ****************************************************************************/ +static struct resource orion_xor1_shared_resources[] = { + { + .name = "xor 1 low", + .flags = IORESOURCE_MEM, + }, { + .name = "xor 1 high", + .flags = IORESOURCE_MEM, + }, { + .name = "irq channel 0", + .flags = IORESOURCE_IRQ, + }, { + .name = "irq channel 1", + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mv_xor_channel_data orion_xor1_channels_data[2]; + +static struct mv_xor_platform_data orion_xor1_pdata = { + .channels = orion_xor1_channels_data, +}; + +static struct platform_device orion_xor1_shared = { + .name = MV_XOR_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(orion_xor1_shared_resources), + .resource = orion_xor1_shared_resources, + .dev = { + .dma_mask = &orion_xor_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(64), + .platform_data = &orion_xor1_pdata, + }, +}; + +void __init orion_xor1_init(unsigned long mapbase_low, + unsigned long mapbase_high, + unsigned long irq_0, + unsigned long irq_1) +{ + orion_xor1_shared_resources[0].start = mapbase_low; + orion_xor1_shared_resources[0].end = mapbase_low + 0xff; + orion_xor1_shared_resources[1].start = mapbase_high; + orion_xor1_shared_resources[1].end = mapbase_high + 0xff; + + orion_xor1_shared_resources[2].start = irq_0; + orion_xor1_shared_resources[2].end = irq_0; + orion_xor1_shared_resources[3].start = irq_1; + orion_xor1_shared_resources[3].end = irq_1; + + dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[0].cap_mask); + dma_cap_set(DMA_XOR, orion_xor1_channels_data[0].cap_mask); + + dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[1].cap_mask); + dma_cap_set(DMA_XOR, orion_xor1_channels_data[1].cap_mask); + + platform_device_register(&orion_xor1_shared); +} + +/***************************************************************************** + * EHCI + ****************************************************************************/ +static struct orion_ehci_data orion_ehci_data; +static u64 ehci_dmamask = DMA_BIT_MASK(32); + + +/***************************************************************************** + * EHCI0 + ****************************************************************************/ +static struct resource orion_ehci_resources[2]; + +static struct platform_device orion_ehci = { + .name = "orion-ehci", + .id = 0, + .dev = { + .dma_mask = &ehci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &orion_ehci_data, + }, +}; + +void __init orion_ehci_init(unsigned long mapbase, + unsigned long irq, + enum orion_ehci_phy_ver phy_version) +{ + orion_ehci_data.phy_version = phy_version; + fill_resources(&orion_ehci, orion_ehci_resources, mapbase, SZ_4K - 1, + irq); + + platform_device_register(&orion_ehci); +} + +/***************************************************************************** + * EHCI1 + ****************************************************************************/ +static struct resource orion_ehci_1_resources[2]; + +static struct platform_device orion_ehci_1 = { + .name = "orion-ehci", + .id = 1, + .dev = { + .dma_mask = &ehci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &orion_ehci_data, + }, +}; + +void __init orion_ehci_1_init(unsigned long mapbase, + unsigned long irq) +{ + fill_resources(&orion_ehci_1, orion_ehci_1_resources, + mapbase, SZ_4K - 1, irq); + + platform_device_register(&orion_ehci_1); +} + +/***************************************************************************** + * EHCI2 + ****************************************************************************/ +static struct resource orion_ehci_2_resources[2]; + +static struct platform_device orion_ehci_2 = { + .name = "orion-ehci", + .id = 2, + .dev = { + .dma_mask = &ehci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &orion_ehci_data, + }, +}; + +void __init orion_ehci_2_init(unsigned long mapbase, + unsigned long irq) +{ + fill_resources(&orion_ehci_2, orion_ehci_2_resources, + mapbase, SZ_4K - 1, irq); + + platform_device_register(&orion_ehci_2); +} + +/***************************************************************************** + * SATA + ****************************************************************************/ +static struct resource orion_sata_resources[2] = { + { + .name = "sata base", + }, { + .name = "sata irq", + }, +}; + +static struct platform_device orion_sata = { + .name = "sata_mv", + .id = 0, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init orion_sata_init(struct mv_sata_platform_data *sata_data, + unsigned long mapbase, + unsigned long irq) +{ + orion_sata.dev.platform_data = sata_data; + fill_resources(&orion_sata, orion_sata_resources, + mapbase, 0x5000 - 1, irq); + + platform_device_register(&orion_sata); +} + +/***************************************************************************** + * Cryptographic Engines and Security Accelerator (CESA) + ****************************************************************************/ +static struct resource orion_crypto_resources[] = { + { + .name = "regs", + }, { + .name = "crypto interrupt", + }, { + .name = "sram", + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device orion_crypto = { + .name = "mv_crypto", + .id = -1, +}; + +void __init orion_crypto_init(unsigned long mapbase, + unsigned long srambase, + unsigned long sram_size, + unsigned long irq) +{ + fill_resources(&orion_crypto, orion_crypto_resources, + mapbase, 0xffff, irq); + orion_crypto.num_resources = 3; + orion_crypto_resources[2].start = srambase; + orion_crypto_resources[2].end = srambase + sram_size - 1; + + platform_device_register(&orion_crypto); +} diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index 0d12c216476..b61a3bcc2fa 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -8,236 +8,323 @@ * warranty of any kind, whether express or implied. */ +#define DEBUG + #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/bitops.h> #include <linux/io.h> -#include <asm/gpio.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <plat/orion-gpio.h> -static DEFINE_SPINLOCK(gpio_lock); -static const char *gpio_label[GPIO_MAX]; /* non null for allocated GPIOs */ -static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)]; +/* + * GPIO unit register offsets. + */ +#define GPIO_OUT_OFF 0x0000 +#define GPIO_IO_CONF_OFF 0x0004 +#define GPIO_BLINK_EN_OFF 0x0008 +#define GPIO_IN_POL_OFF 0x000c +#define GPIO_DATA_IN_OFF 0x0010 +#define GPIO_EDGE_CAUSE_OFF 0x0014 +#define GPIO_EDGE_MASK_OFF 0x0018 +#define GPIO_LEVEL_MASK_OFF 0x001c + +struct orion_gpio_chip { + struct gpio_chip chip; + spinlock_t lock; + void __iomem *base; + unsigned long valid_input; + unsigned long valid_output; + int mask_offset; + int secondary_irq_base; + struct irq_domain *domain; +}; -static inline void __set_direction(unsigned pin, int input) +static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip) { - u32 u; + return ochip->base + GPIO_OUT_OFF; +} - u = readl(GPIO_IO_CONF(pin)); - if (input) - u |= 1 << (pin & 31); - else - u &= ~(1 << (pin & 31)); - writel(u, GPIO_IO_CONF(pin)); +static void __iomem *GPIO_IO_CONF(struct orion_gpio_chip *ochip) +{ + return ochip->base + GPIO_IO_CONF_OFF; } -static void __set_level(unsigned pin, int high) +static void __iomem *GPIO_BLINK_EN(struct orion_gpio_chip *ochip) { - u32 u; + return ochip->base + GPIO_BLINK_EN_OFF; +} - u = readl(GPIO_OUT(pin)); - if (high) - u |= 1 << (pin & 31); - else - u &= ~(1 << (pin & 31)); - writel(u, GPIO_OUT(pin)); +static void __iomem *GPIO_IN_POL(struct orion_gpio_chip *ochip) +{ + return ochip->base + GPIO_IN_POL_OFF; } +static void __iomem *GPIO_DATA_IN(struct orion_gpio_chip *ochip) +{ + return ochip->base + GPIO_DATA_IN_OFF; +} -/* - * GENERIC_GPIO primitives. - */ -int gpio_direction_input(unsigned pin) +static void __iomem *GPIO_EDGE_CAUSE(struct orion_gpio_chip *ochip) { - unsigned long flags; + return ochip->base + GPIO_EDGE_CAUSE_OFF; +} - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return -EINVAL; - } +static void __iomem *GPIO_EDGE_MASK(struct orion_gpio_chip *ochip) +{ + return ochip->base + ochip->mask_offset + GPIO_EDGE_MASK_OFF; +} - spin_lock_irqsave(&gpio_lock, flags); +static void __iomem *GPIO_LEVEL_MASK(struct orion_gpio_chip *ochip) +{ + return ochip->base + ochip->mask_offset + GPIO_LEVEL_MASK_OFF; +} - /* - * Some callers might not have used gpio_request(), - * so flag this pin as requested now. - */ - if (gpio_label[pin] == NULL) - gpio_label[pin] = "?"; - /* - * Configure GPIO direction. - */ - __set_direction(pin, 1); +static struct orion_gpio_chip orion_gpio_chips[2]; +static int orion_gpio_chip_count; - spin_unlock_irqrestore(&gpio_lock, flags); +static inline void +__set_direction(struct orion_gpio_chip *ochip, unsigned pin, int input) +{ + u32 u; - return 0; + u = readl(GPIO_IO_CONF(ochip)); + if (input) + u |= 1 << pin; + else + u &= ~(1 << pin); + writel(u, GPIO_IO_CONF(ochip)); } -EXPORT_SYMBOL(gpio_direction_input); -int gpio_direction_output(unsigned pin, int value) +static void __set_level(struct orion_gpio_chip *ochip, unsigned pin, int high) { - unsigned long flags; u32 u; - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return -EINVAL; - } + u = readl(GPIO_OUT(ochip)); + if (high) + u |= 1 << pin; + else + u &= ~(1 << pin); + writel(u, GPIO_OUT(ochip)); +} - spin_lock_irqsave(&gpio_lock, flags); +static inline void +__set_blinking(struct orion_gpio_chip *ochip, unsigned pin, int blink) +{ + u32 u; - /* - * Some callers might not have used gpio_request(), - * so flag this pin as requested now. - */ - if (gpio_label[pin] == NULL) - gpio_label[pin] = "?"; + u = readl(GPIO_BLINK_EN(ochip)); + if (blink) + u |= 1 << pin; + else + u &= ~(1 << pin); + writel(u, GPIO_BLINK_EN(ochip)); +} - /* - * Disable blinking. - */ - u = readl(GPIO_BLINK_EN(pin)); - u &= ~(1 << (pin & 31)); - writel(u, GPIO_BLINK_EN(pin)); +static inline int +orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode) +{ + if (pin >= ochip->chip.ngpio) + goto err_out; - /* - * Configure GPIO output value. - */ - __set_level(pin, value); + if ((mode & GPIO_INPUT_OK) && !test_bit(pin, &ochip->valid_input)) + goto err_out; - /* - * Configure GPIO direction. - */ - __set_direction(pin, 0); + if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, &ochip->valid_output)) + goto err_out; - spin_unlock_irqrestore(&gpio_lock, flags); + return 1; - return 0; +err_out: + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return false; } -EXPORT_SYMBOL(gpio_direction_output); -int gpio_get_value(unsigned pin) +/* + * GPIO primitives. + */ +static int orion_gpio_request(struct gpio_chip *chip, unsigned pin) { - int val; + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); - if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31))) - val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin)); - else - val = readl(GPIO_OUT(pin)); + if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) || + orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK)) + return 0; - return (val >> (pin & 31)) & 1; + return -EINVAL; } -EXPORT_SYMBOL(gpio_get_value); -void gpio_set_value(unsigned pin, int value) +static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin) { + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); unsigned long flags; - u32 u; - spin_lock_irqsave(&gpio_lock, flags); + if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK)) + return -EINVAL; - /* - * Disable blinking. - */ - u = readl(GPIO_BLINK_EN(pin)); - u &= ~(1 << (pin & 31)); - writel(u, GPIO_BLINK_EN(pin)); + spin_lock_irqsave(&ochip->lock, flags); + __set_direction(ochip, pin, 1); + spin_unlock_irqrestore(&ochip->lock, flags); - /* - * Configure GPIO output value. - */ - __set_level(pin, value); + return 0; +} - spin_unlock_irqrestore(&gpio_lock, flags); +static int orion_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); + int val; + + if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) { + val = readl(GPIO_DATA_IN(ochip)) ^ readl(GPIO_IN_POL(ochip)); + } else { + val = readl(GPIO_OUT(ochip)); + } + + return (val >> pin) & 1; } -EXPORT_SYMBOL(gpio_set_value); -int gpio_request(unsigned pin, const char *label) +static int +orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value) { + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); unsigned long flags; - int ret; - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); + if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK)) return -EINVAL; - } - spin_lock_irqsave(&gpio_lock, flags); - if (gpio_label[pin] == NULL) { - gpio_label[pin] = label ? label : "?"; - ret = 0; - } else { - pr_debug("%s: GPIO %d already used as %s\n", - __func__, pin, gpio_label[pin]); - ret = -EBUSY; - } - spin_unlock_irqrestore(&gpio_lock, flags); + spin_lock_irqsave(&ochip->lock, flags); + __set_blinking(ochip, pin, 0); + __set_level(ochip, pin, value); + __set_direction(ochip, pin, 0); + spin_unlock_irqrestore(&ochip->lock, flags); - return ret; + return 0; } -EXPORT_SYMBOL(gpio_request); -void gpio_free(unsigned pin) +static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value) { - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return; - } + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); + unsigned long flags; - if (gpio_label[pin] == NULL) - pr_warning("%s: GPIO %d already freed\n", __func__, pin); - else - gpio_label[pin] = NULL; + spin_lock_irqsave(&ochip->lock, flags); + __set_level(ochip, pin, value); + spin_unlock_irqrestore(&ochip->lock, flags); } -EXPORT_SYMBOL(gpio_free); +static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +{ + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); + + return irq_create_mapping(ochip->domain, + ochip->secondary_irq_base + pin); +} /* * Orion-specific GPIO API extensions. */ +static struct orion_gpio_chip *orion_gpio_chip_find(int pin) +{ + int i; + + for (i = 0; i < orion_gpio_chip_count; i++) { + struct orion_gpio_chip *ochip = orion_gpio_chips + i; + struct gpio_chip *chip = &ochip->chip; + + if (pin >= chip->base && pin < chip->base + chip->ngpio) + return ochip; + } + + return NULL; +} + void __init orion_gpio_set_unused(unsigned pin) { - /* - * Configure as output, drive low. - */ - __set_level(pin, 0); - __set_direction(pin, 0); + struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin); + + if (ochip == NULL) + return; + + pin -= ochip->chip.base; + + /* Configure as output, drive low. */ + __set_level(ochip, pin, 0); + __set_direction(ochip, pin, 0); } -void __init orion_gpio_set_valid(unsigned pin, int valid) +void __init orion_gpio_set_valid(unsigned pin, int mode) { - if (valid) - __set_bit(pin, gpio_valid); + struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin); + + if (ochip == NULL) + return; + + pin -= ochip->chip.base; + + if (mode == 1) + mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK; + + if (mode & GPIO_INPUT_OK) + __set_bit(pin, &ochip->valid_input); else - __clear_bit(pin, gpio_valid); + __clear_bit(pin, &ochip->valid_input); + + if (mode & GPIO_OUTPUT_OK) + __set_bit(pin, &ochip->valid_output); + else + __clear_bit(pin, &ochip->valid_output); } void orion_gpio_set_blink(unsigned pin, int blink) { + struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin); unsigned long flags; - u32 u; - spin_lock_irqsave(&gpio_lock, flags); + if (ochip == NULL) + return; - /* - * Set output value to zero. - */ - __set_level(pin, 0); + spin_lock_irqsave(&ochip->lock, flags); + __set_level(ochip, pin & 31, 0); + __set_blinking(ochip, pin & 31, blink); + spin_unlock_irqrestore(&ochip->lock, flags); +} +EXPORT_SYMBOL(orion_gpio_set_blink); - u = readl(GPIO_BLINK_EN(pin)); - if (blink) - u |= 1 << (pin & 31); - else - u &= ~(1 << (pin & 31)); - writel(u, GPIO_BLINK_EN(pin)); +#define ORION_BLINK_HALF_PERIOD 100 /* ms */ + +int orion_gpio_led_blink_set(unsigned gpio, int state, + unsigned long *delay_on, unsigned long *delay_off) +{ - spin_unlock_irqrestore(&gpio_lock, flags); + if (delay_on && delay_off && !*delay_on && !*delay_off) + *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD; + + switch (state) { + case GPIO_LED_NO_BLINK_LOW: + case GPIO_LED_NO_BLINK_HIGH: + orion_gpio_set_blink(gpio, 0); + gpio_set_value(gpio, state); + break; + case GPIO_LED_BLINK: + orion_gpio_set_blink(gpio, 1); + } + return 0; } -EXPORT_SYMBOL(orion_gpio_set_blink); +EXPORT_SYMBOL_GPL(orion_gpio_led_blink_set); /***************************************************************************** @@ -266,127 +353,247 @@ EXPORT_SYMBOL(orion_gpio_set_blink); * ****************************************************************************/ -static void gpio_irq_ack(u32 irq) -{ - int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK; - if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { - int pin = irq_to_gpio(irq); - writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin)); - } -} - -static void gpio_irq_mask(u32 irq) -{ - int pin = irq_to_gpio(irq); - int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK; - u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ? - GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin); - u32 u = readl(reg); - u &= ~(1 << (pin & 31)); - writel(u, reg); -} - -static void gpio_irq_unmask(u32 irq) -{ - int pin = irq_to_gpio(irq); - int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK; - u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ? - GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin); - u32 u = readl(reg); - u |= 1 << (pin & 31); - writel(u, reg); -} - -static int gpio_irq_set_type(u32 irq, u32 type) +static int gpio_irq_set_type(struct irq_data *d, u32 type) { - int pin = irq_to_gpio(irq); - struct irq_desc *desc; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + struct orion_gpio_chip *ochip = gc->private; + int pin; u32 u; - u = readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31)); + pin = d->hwirq - ochip->secondary_irq_base; + + u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); if (!u) { - printk(KERN_ERR "orion gpio_irq_set_type failed " - "(irq %d, pin %d).\n", irq, pin); return -EINVAL; } - desc = irq_desc + irq; - - /* - * Set edge/level type. - */ - if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { - desc->handle_irq = handle_edge_irq; - } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - desc->handle_irq = handle_level_irq; - } else { - printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type); + type &= IRQ_TYPE_SENSE_MASK; + if (type == IRQ_TYPE_NONE) return -EINVAL; - } + + /* Check if we need to change chip and handler */ + if (!(ct->type & type)) + if (irq_setup_alt_chip(d, type)) + return -EINVAL; /* * Configure interrupt polarity. */ if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) { - u = readl(GPIO_IN_POL(pin)); - u &= ~(1 << (pin & 31)); - writel(u, GPIO_IN_POL(pin)); + u = readl(GPIO_IN_POL(ochip)); + u &= ~(1 << pin); + writel(u, GPIO_IN_POL(ochip)); } else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) { - u = readl(GPIO_IN_POL(pin)); - u |= 1 << (pin & 31); - writel(u, GPIO_IN_POL(pin)); + u = readl(GPIO_IN_POL(ochip)); + u |= 1 << pin; + writel(u, GPIO_IN_POL(ochip)); } else if (type == IRQ_TYPE_EDGE_BOTH) { u32 v; - v = readl(GPIO_IN_POL(pin)) ^ readl(GPIO_DATA_IN(pin)); + v = readl(GPIO_IN_POL(ochip)) ^ readl(GPIO_DATA_IN(ochip)); /* * set initial polarity based on current input level */ - u = readl(GPIO_IN_POL(pin)); - if (v & (1 << (pin & 31))) - u |= 1 << (pin & 31); /* falling */ + u = readl(GPIO_IN_POL(ochip)); + if (v & (1 << pin)) + u |= 1 << pin; /* falling */ else - u &= ~(1 << (pin & 31)); /* rising */ - writel(u, GPIO_IN_POL(pin)); + u &= ~(1 << pin); /* rising */ + writel(u, GPIO_IN_POL(ochip)); } - - desc->status = (desc->status & ~IRQ_TYPE_SENSE_MASK) | type; - return 0; } -struct irq_chip orion_gpio_irq_chip = { - .name = "orion_gpio", - .ack = gpio_irq_ack, - .mask = gpio_irq_mask, - .unmask = gpio_irq_unmask, - .set_type = gpio_irq_set_type, -}; - -void orion_gpio_irq_handler(int pinoff) +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - u32 cause; - int pin; + struct orion_gpio_chip *ochip = irq_get_handler_data(irq); + u32 cause, type; + int i; + + if (ochip == NULL) + return; - cause = readl(GPIO_DATA_IN(pinoff)) & readl(GPIO_LEVEL_MASK(pinoff)); - cause |= readl(GPIO_EDGE_CAUSE(pinoff)) & readl(GPIO_EDGE_MASK(pinoff)); + cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip)); + cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip)); - for (pin = pinoff; pin < pinoff + 8; pin++) { - int irq = gpio_to_irq(pin); - struct irq_desc *desc = irq_desc + irq; + for (i = 0; i < ochip->chip.ngpio; i++) { + int irq; - if (!(cause & (1 << (pin & 31)))) + irq = ochip->secondary_irq_base + i; + + if (!(cause & (1 << i))) continue; - if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + type = irq_get_trigger_type(irq); + if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { /* Swap polarity (race with GPIO line) */ u32 polarity; - polarity = readl(GPIO_IN_POL(pin)); - polarity ^= 1 << (pin & 31); - writel(polarity, GPIO_IN_POL(pin)); + polarity = readl(GPIO_IN_POL(ochip)); + polarity ^= 1 << i; + writel(polarity, GPIO_IN_POL(ochip)); + } + generic_handle_irq(irq); + } +} + +#ifdef CONFIG_DEBUG_FS +#include <linux/seq_file.h> + +static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct orion_gpio_chip *ochip = + container_of(chip, struct orion_gpio_chip, chip); + u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; + int i; + + out = readl_relaxed(GPIO_OUT(ochip)); + io_conf = readl_relaxed(GPIO_IO_CONF(ochip)); + blink = readl_relaxed(GPIO_BLINK_EN(ochip)); + in_pol = readl_relaxed(GPIO_IN_POL(ochip)); + data_in = readl_relaxed(GPIO_DATA_IN(ochip)); + cause = readl_relaxed(GPIO_EDGE_CAUSE(ochip)); + edg_msk = readl_relaxed(GPIO_EDGE_MASK(ochip)); + lvl_msk = readl_relaxed(GPIO_LEVEL_MASK(ochip)); + + for (i = 0; i < chip->ngpio; i++) { + const char *label; + u32 msk; + bool is_out; + + label = gpiochip_is_requested(chip, i); + if (!label) + continue; + + msk = 1 << i; + is_out = !(io_conf & msk); + + seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); + + if (is_out) { + seq_printf(s, " out %s %s\n", + out & msk ? "hi" : "lo", + blink & msk ? "(blink )" : ""); + continue; } - desc_handle_irq(irq, desc); + + seq_printf(s, " in %s (act %s) - IRQ", + (data_in ^ in_pol) & msk ? "hi" : "lo", + in_pol & msk ? "lo" : "hi"); + if (!((edg_msk | lvl_msk) & msk)) { + seq_printf(s, " disabled\n"); + continue; + } + if (edg_msk & msk) + seq_printf(s, " edge "); + if (lvl_msk & msk) + seq_printf(s, " level"); + seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); } } +#else +#define orion_gpio_dbg_show NULL +#endif + +void __init orion_gpio_init(struct device_node *np, + int gpio_base, int ngpio, + void __iomem *base, int mask_offset, + int secondary_irq_base, + int irqs[4]) +{ + struct orion_gpio_chip *ochip; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + char gc_label[16]; + int i; + + if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) + return; + + snprintf(gc_label, sizeof(gc_label), "orion_gpio%d", + orion_gpio_chip_count); + + ochip = orion_gpio_chips + orion_gpio_chip_count; + ochip->chip.label = kstrdup(gc_label, GFP_KERNEL); + ochip->chip.request = orion_gpio_request; + ochip->chip.direction_input = orion_gpio_direction_input; + ochip->chip.get = orion_gpio_get; + ochip->chip.direction_output = orion_gpio_direction_output; + ochip->chip.set = orion_gpio_set; + ochip->chip.to_irq = orion_gpio_to_irq; + ochip->chip.base = gpio_base; + ochip->chip.ngpio = ngpio; + ochip->chip.can_sleep = 0; +#ifdef CONFIG_OF + ochip->chip.of_node = np; +#endif + ochip->chip.dbg_show = orion_gpio_dbg_show; + + spin_lock_init(&ochip->lock); + ochip->base = (void __iomem *)base; + ochip->valid_input = 0; + ochip->valid_output = 0; + ochip->mask_offset = mask_offset; + ochip->secondary_irq_base = secondary_irq_base; + + gpiochip_add(&ochip->chip); + + /* + * Mask and clear GPIO interrupts. + */ + writel(0, GPIO_EDGE_CAUSE(ochip)); + writel(0, GPIO_EDGE_MASK(ochip)); + writel(0, GPIO_LEVEL_MASK(ochip)); + + /* Setup the interrupt handlers. Each chip can have up to 4 + * interrupt handlers, with each handler dealing with 8 GPIO + * pins. */ + + for (i = 0; i < 4; i++) { + if (irqs[i]) { + irq_set_handler_data(irqs[i], ochip); + irq_set_chained_handler(irqs[i], gpio_irq_handler); + } + } + + gc = irq_alloc_generic_chip("orion_gpio_irq", 2, + secondary_irq_base, + ochip->base, handle_level_irq); + gc->private = ochip; + ct = gc->chip_types; + ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; + ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_set_type = gpio_irq_set_type; + ct->chip.name = ochip->chip.label; + + ct++; + ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF; + ct->regs.ack = GPIO_EDGE_CAUSE_OFF; + ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + ct->chip.irq_ack = irq_gc_ack_clr_bit; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_set_type = gpio_irq_set_type; + ct->handler = handle_edge_irq; + ct->chip.name = ochip->chip.label; + + irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); + + /* Setup irq domain on top of the generic chip. */ + ochip->domain = irq_domain_add_legacy(np, + ochip->chip.ngpio, + ochip->secondary_irq_base, + ochip->secondary_irq_base, + &irq_domain_simple_ops, + ochip); + if (!ochip->domain) + panic("%s: couldn't allocate irq domain (DT).\n", + ochip->chip.label); + + orion_gpio_chip_count++; +} diff --git a/arch/arm/plat-orion/include/plat/addr-map.h b/arch/arm/plat-orion/include/plat/addr-map.h new file mode 100644 index 00000000000..b76c06569fe --- /dev/null +++ b/arch/arm/plat-orion/include/plat/addr-map.h @@ -0,0 +1,54 @@ +/* + * arch/arm/plat-orion/include/plat/addr-map.h + * + * Marvell Orion SoC address map handling. + * + * 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. + */ + +#ifndef __PLAT_ADDR_MAP_H +#define __PLAT_ADDR_MAP_H + +extern struct mbus_dram_target_info orion_mbus_dram_info; + +struct orion_addr_map_cfg { + const int num_wins; /* Total number of windows */ + const int remappable_wins; + void __iomem *bridge_virt_base; + int hw_io_coherency; + + /* If NULL, the default cpu_win_can_remap will be used, using + the value in remappable_wins */ + int (*cpu_win_can_remap) (const struct orion_addr_map_cfg *cfg, + const int win); + /* If NULL, the default win_cfg_base will be used, using the + value in bridge_virt_base */ + void __iomem *(*win_cfg_base) (const struct orion_addr_map_cfg *cfg, + const int win); +}; + +/* + * Information needed to setup one address mapping. + */ +struct orion_addr_map_info { + const int win; + const u32 base; + const u32 size; + const u8 target; + const u8 attr; + const int remap; +}; + +void __init orion_config_wins(struct orion_addr_map_cfg *cfg, + const struct orion_addr_map_info *info); + +void __init orion_setup_cpu_win(const struct orion_addr_map_cfg *cfg, + const int win, const u32 base, + const u32 size, const u8 target, + const u8 attr, const int remap); + +void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg, + const void __iomem *ddr_window_cpu_base); +#endif diff --git a/arch/arm/plat-orion/include/plat/cache-feroceon-l2.h b/arch/arm/plat-orion/include/plat/cache-feroceon-l2.h deleted file mode 100644 index 06f982d5569..00000000000 --- a/arch/arm/plat-orion/include/plat/cache-feroceon-l2.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/cache-feroceon-l2.h - * - * Copyright (C) 2008 Marvell Semiconductor - * - * 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. - */ - -extern void __init feroceon_l2_init(int l2_wt_override); diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h new file mode 100644 index 00000000000..d9a24f605a2 --- /dev/null +++ b/arch/arm/plat-orion/include/plat/common.h @@ -0,0 +1,113 @@ +/* + * arch/arm/plat-orion/include/plat/common.h + * + * Marvell Orion SoC common setup code used by different mach-/common.c + * + * 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. + */ + +#ifndef __PLAT_COMMON_H +#include <linux/mv643xx_eth.h> +#include <linux/platform_data/usb-ehci-orion.h> + +struct dsa_platform_data; +struct mv_sata_platform_data; + +void __init orion_uart0_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk); + +void __init orion_uart1_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk); + +void __init orion_uart2_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk); + +void __init orion_uart3_init(void __iomem *membase, + resource_size_t mapbase, + unsigned int irq, + struct clk *clk); + +void __init orion_rtc_init(unsigned long mapbase, + unsigned long irq); + +void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err, + unsigned int tx_csum_limit); + +void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err, + unsigned int tx_csum_limit); + +void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err); + +void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, + unsigned long mapbase, + unsigned long irq, + unsigned long irq_err); + +void __init orion_ge00_switch_init(struct dsa_platform_data *d, + int irq); + +void __init orion_i2c_init(unsigned long mapbase, + unsigned long irq, + unsigned long freq_m); + +void __init orion_i2c_1_init(unsigned long mapbase, + unsigned long irq, + unsigned long freq_m); + +void __init orion_spi_init(unsigned long mapbase); + +void __init orion_spi_1_init(unsigned long mapbase); + +void __init orion_wdt_init(void); + +void __init orion_xor0_init(unsigned long mapbase_low, + unsigned long mapbase_high, + unsigned long irq_0, + unsigned long irq_1); + +void __init orion_xor1_init(unsigned long mapbase_low, + unsigned long mapbase_high, + unsigned long irq_0, + unsigned long irq_1); + +void __init orion_ehci_init(unsigned long mapbase, + unsigned long irq, + enum orion_ehci_phy_ver phy_version); + +void __init orion_ehci_1_init(unsigned long mapbase, + unsigned long irq); + +void __init orion_ehci_2_init(unsigned long mapbase, + unsigned long irq); + +void __init orion_sata_init(struct mv_sata_platform_data *sata_data, + unsigned long mapbase, + unsigned long irq); + +void __init orion_crypto_init(unsigned long mapbase, + unsigned long srambase, + unsigned long sram_size, + unsigned long irq); + +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk); + +void __init orion_clkdev_init(struct clk *tclk); +#endif diff --git a/arch/arm/plat-orion/include/plat/ehci-orion.h b/arch/arm/plat-orion/include/plat/ehci-orion.h deleted file mode 100644 index 4ec668e7746..00000000000 --- a/arch/arm/plat-orion/include/plat/ehci-orion.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/ehci-orion.h - * - * 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. - */ - -#ifndef __PLAT_EHCI_ORION_H -#define __PLAT_EHCI_ORION_H - -#include <linux/mbus.h> - -enum orion_ehci_phy_ver { - EHCI_PHY_ORION, - EHCI_PHY_DD, - EHCI_PHY_KW, - EHCI_PHY_NA, -}; - -struct orion_ehci_data { - struct mbus_dram_target_info *dram; - enum orion_ehci_phy_ver phy_version; -}; - - -#endif diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h deleted file mode 100644 index ec743e82c87..00000000000 --- a/arch/arm/plat-orion/include/plat/gpio.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/gpio.h - * - * Marvell Orion SoC GPIO handling. - * - * 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. - */ - -#ifndef __PLAT_GPIO_H -#define __PLAT_GPIO_H - -/* - * GENERIC_GPIO primitives. - */ -int gpio_request(unsigned pin, const char *label); -void gpio_free(unsigned pin); -int gpio_direction_input(unsigned pin); -int gpio_direction_output(unsigned pin, int value); -int gpio_get_value(unsigned pin); -void gpio_set_value(unsigned pin, int value); - -/* - * Orion-specific GPIO API extensions. - */ -void orion_gpio_set_unused(unsigned pin); -void orion_gpio_set_valid(unsigned pin, int valid); -void orion_gpio_set_blink(unsigned pin, int blink); - -/* - * GPIO interrupt handling. - */ -extern struct irq_chip orion_gpio_irq_chip; -void orion_gpio_irq_handler(int irqoff); - - -#endif diff --git a/arch/arm/plat-orion/include/plat/irq.h b/arch/arm/plat-orion/include/plat/irq.h index f05eeab9496..96be19e9bd9 100644 --- a/arch/arm/plat-orion/include/plat/irq.h +++ b/arch/arm/plat-orion/include/plat/irq.h @@ -12,6 +12,4 @@ #define __PLAT_IRQ_H void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr); - - #endif diff --git a/arch/arm/plat-orion/include/plat/mpp.h b/arch/arm/plat-orion/include/plat/mpp.h new file mode 100644 index 00000000000..254552fee88 --- /dev/null +++ b/arch/arm/plat-orion/include/plat/mpp.h @@ -0,0 +1,34 @@ +/* + * arch/arm/plat-orion/include/plat/mpp.h + * + * Marvell Orion SoC MPP handling. + * + * 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. + */ + +#ifndef __PLAT_MPP_H +#define __PLAT_MPP_H + +#define MPP_NUM(x) ((x) & 0xff) +#define MPP_SEL(x) (((x) >> 8) & 0xf) + +/* This is the generic MPP macro, without any variant information. + Each machine architecture is expected to extend this with further + bit fields indicating which MPP configurations are valid for a + specific variant. */ + +#define GENERIC_MPP(_num, _sel, _in, _out) ( \ + /* MPP number */ ((_num) & 0xff) | \ + /* MPP select value */ (((_sel) & 0xf) << 8) | \ + /* may be input signal */ ((!!(_in)) << 12) | \ + /* may be output signal */ ((!!(_out)) << 13)) + +#define MPP_INPUT_MASK GENERIC_MPP(0, 0x0, 1, 0) +#define MPP_OUTPUT_MASK GENERIC_MPP(0, 0x0, 0, 1) + +void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask, + unsigned int mpp_max, void __iomem *dev_bus); + +#endif diff --git a/arch/arm/plat-orion/include/plat/mv_xor.h b/arch/arm/plat-orion/include/plat/mv_xor.h deleted file mode 100644 index bd5f3bdb4ae..00000000000 --- a/arch/arm/plat-orion/include/plat/mv_xor.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/mv_xor.h - * - * Marvell XOR platform device data definition file. - */ - -#ifndef __PLAT_MV_XOR_H -#define __PLAT_MV_XOR_H - -#include <linux/dmaengine.h> -#include <linux/mbus.h> - -#define MV_XOR_SHARED_NAME "mv_xor_shared" -#define MV_XOR_NAME "mv_xor" - -struct mbus_dram_target_info; - -struct mv_xor_platform_shared_data { - struct mbus_dram_target_info *dram; -}; - -struct mv_xor_platform_data { - struct platform_device *shared; - int hw_id; - dma_cap_mask_t cap_mask; - size_t pool_size; -}; - - -#endif diff --git a/arch/arm/plat-orion/include/plat/orion-gpio.h b/arch/arm/plat-orion/include/plat/orion-gpio.h new file mode 100644 index 00000000000..e763988b04b --- /dev/null +++ b/arch/arm/plat-orion/include/plat/orion-gpio.h @@ -0,0 +1,36 @@ +/* + * arch/arm/plat-orion/include/plat/orion-gpio.h + * + * Marvell Orion SoC GPIO handling. + * + * 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. + */ + +#ifndef __PLAT_GPIO_H +#define __PLAT_GPIO_H + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/irqdomain.h> +/* + * Orion-specific GPIO API extensions. + */ +void orion_gpio_set_unused(unsigned pin); +void orion_gpio_set_blink(unsigned pin, int blink); +int orion_gpio_led_blink_set(unsigned gpio, int state, + unsigned long *delay_on, unsigned long *delay_off); + +#define GPIO_INPUT_OK (1 << 0) +#define GPIO_OUTPUT_OK (1 << 1) +void orion_gpio_set_valid(unsigned pin, int mode); + +/* Initialize gpiolib. */ +void __init orion_gpio_init(struct device_node *np, + int gpio_base, int ngpio, + void __iomem *base, int mask_offset, + int secondary_irq_base, + int irq[4]); + +#endif diff --git a/arch/arm/plat-orion/include/plat/orion_nand.h b/arch/arm/plat-orion/include/plat/orion_nand.h deleted file mode 100644 index d6a4cfa3778..00000000000 --- a/arch/arm/plat-orion/include/plat/orion_nand.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/orion_nand.h - * - * 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. - */ - -#ifndef __PLAT_ORION_NAND_H -#define __PLAT_ORION_NAND_H - -/* - * Device bus NAND private data - */ -struct orion_nand_data { - struct mtd_partition *parts; - u32 nr_parts; - u8 ale; /* address line number connected to ALE */ - u8 cle; /* address line number connected to CLE */ - u8 width; /* buswidth */ - u8 chip_delay; -}; - - -#endif diff --git a/arch/arm/plat-orion/include/plat/pcie.h b/arch/arm/plat-orion/include/plat/pcie.h index 3ebfef72b4e..fe5b9e86274 100644 --- a/arch/arm/plat-orion/include/plat/pcie.h +++ b/arch/arm/plat-orion/include/plat/pcie.h @@ -11,14 +11,16 @@ #ifndef __PLAT_PCIE_H #define __PLAT_PCIE_H +struct pci_bus; + u32 orion_pcie_dev_id(void __iomem *base); u32 orion_pcie_rev(void __iomem *base); int orion_pcie_link_up(void __iomem *base); int orion_pcie_x4_mode(void __iomem *base); int orion_pcie_get_local_bus_nr(void __iomem *base); void orion_pcie_set_local_bus_nr(void __iomem *base, int nr); -void orion_pcie_setup(void __iomem *base, - struct mbus_dram_target_info *dram); +void orion_pcie_reset(void __iomem *base); +void orion_pcie_setup(void __iomem *base); int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus, u32 devfn, int where, int size, u32 *val); int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus, diff --git a/arch/arm/plat-orion/include/plat/time.h b/arch/arm/plat-orion/include/plat/time.h index c06ca35f361..07527e417c6 100644 --- a/arch/arm/plat-orion/include/plat/time.h +++ b/arch/arm/plat-orion/include/plat/time.h @@ -11,7 +11,10 @@ #ifndef __PLAT_TIME_H #define __PLAT_TIME_H -void orion_time_init(unsigned int irq, unsigned int tclk); +void orion_time_set_base(void __iomem *timer_base); + +void orion_time_init(void __iomem *bridge_base, u32 bridge_timer1_clr_mask, + unsigned int irq, unsigned int tclk); #endif diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c index 3f9d34fc738..8c1fc06007c 100644 --- a/arch/arm/plat-orion/irq.c +++ b/arch/arm/plat-orion/irq.c @@ -11,55 +11,30 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <asm/exception.h> #include <plat/irq.h> - -static void orion_irq_mask(u32 irq) -{ - void __iomem *maskaddr = get_irq_chip_data(irq); - u32 mask; - - mask = readl(maskaddr); - mask &= ~(1 << (irq & 31)); - writel(mask, maskaddr); -} - -static void orion_irq_unmask(u32 irq) -{ - void __iomem *maskaddr = get_irq_chip_data(irq); - u32 mask; - - mask = readl(maskaddr); - mask |= 1 << (irq & 31); - writel(mask, maskaddr); -} - -static struct irq_chip orion_irq_chip = { - .name = "orion_irq", - .mask = orion_irq_mask, - .mask_ack = orion_irq_mask, - .unmask = orion_irq_unmask, -}; +#include <plat/orion-gpio.h> +#include <mach/bridge-regs.h> void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr) { - unsigned int i; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; /* * Mask all interrupts initially. */ writel(0, maskaddr); - /* - * Register IRQ sources. - */ - for (i = 0; i < 32; i++) { - unsigned int irq = irq_start + i; - - set_irq_chip(irq, &orion_irq_chip); - set_irq_chip_data(irq, maskaddr); - set_irq_handler(irq, handle_level_irq); - irq_desc[irq].status |= IRQ_LEVEL; - set_irq_flags(irq, IRQF_VALID); - } + gc = irq_alloc_generic_chip("orion_irq", 1, irq_start, maskaddr, + handle_level_irq); + ct = gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); } diff --git a/arch/arm/plat-orion/mpp.c b/arch/arm/plat-orion/mpp.c new file mode 100644 index 00000000000..7310bcfb299 --- /dev/null +++ b/arch/arm/plat-orion/mpp.c @@ -0,0 +1,78 @@ +/* + * arch/arm/plat-orion/mpp.c + * + * MPP functions for Marvell orion SoCs + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/mbus.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <mach/hardware.h> +#include <plat/orion-gpio.h> +#include <plat/mpp.h> + +/* Address of the ith MPP control register */ +static __init void __iomem *mpp_ctrl_addr(unsigned int i, + void __iomem *dev_bus) +{ + return dev_bus + (i) * 4; +} + + +void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask, + unsigned int mpp_max, void __iomem *dev_bus) +{ + unsigned int mpp_nr_regs = (1 + mpp_max/8); + u32 mpp_ctrl[mpp_nr_regs]; + int i; + + printk(KERN_DEBUG "initial MPP regs:"); + for (i = 0; i < mpp_nr_regs; i++) { + mpp_ctrl[i] = readl(mpp_ctrl_addr(i, dev_bus)); + printk(" %08x", mpp_ctrl[i]); + } + printk("\n"); + + for ( ; *mpp_list; mpp_list++) { + unsigned int num = MPP_NUM(*mpp_list); + unsigned int sel = MPP_SEL(*mpp_list); + int shift, gpio_mode; + + if (num > mpp_max) { + printk(KERN_ERR "orion_mpp_conf: invalid MPP " + "number (%u)\n", num); + continue; + } + if (variant_mask && !(*mpp_list & variant_mask)) { + printk(KERN_WARNING + "orion_mpp_conf: requested MPP%u config " + "unavailable on this hardware\n", num); + continue; + } + + shift = (num & 7) << 2; + mpp_ctrl[num / 8] &= ~(0xf << shift); + mpp_ctrl[num / 8] |= sel << shift; + + gpio_mode = 0; + if (*mpp_list & MPP_INPUT_MASK) + gpio_mode |= GPIO_INPUT_OK; + if (*mpp_list & MPP_OUTPUT_MASK) + gpio_mode |= GPIO_OUTPUT_OK; + + orion_gpio_set_valid(num, gpio_mode); + } + + printk(KERN_DEBUG " final MPP regs:"); + for (i = 0; i < mpp_nr_regs; i++) { + writel(mpp_ctrl[i], mpp_ctrl_addr(i, dev_bus)); + printk(" %08x", mpp_ctrl[i]); + } + printk("\n"); +} diff --git a/arch/arm/plat-orion/pcie.c b/arch/arm/plat-orion/pcie.c index d41d41d78ad..8b8c06d2e9c 100644 --- a/arch/arm/plat-orion/pcie.c +++ b/arch/arm/plat-orion/pcie.c @@ -13,6 +13,8 @@ #include <linux/mbus.h> #include <asm/mach/pci.h> #include <plat/pcie.h> +#include <plat/addr-map.h> +#include <linux/delay.h> /* * PCIe unit register offsets. @@ -46,14 +48,16 @@ #define PCIE_STAT_BUS_OFFS 8 #define PCIE_STAT_BUS_MASK 0xff #define PCIE_STAT_LINK_DOWN 1 +#define PCIE_DEBUG_CTRL 0x1a60 +#define PCIE_DEBUG_SOFT_RESET (1<<20) -u32 __init orion_pcie_dev_id(void __iomem *base) +u32 orion_pcie_dev_id(void __iomem *base) { return readl(base + PCIE_DEV_ID_OFF) >> 16; } -u32 __init orion_pcie_rev(void __iomem *base) +u32 orion_pcie_rev(void __iomem *base) { return readl(base + PCIE_DEV_REV_OFF) & 0xff; } @@ -85,17 +89,45 @@ void __init orion_pcie_set_local_bus_nr(void __iomem *base, int nr) writel(stat, base + PCIE_STAT_OFF); } +void __init orion_pcie_reset(void __iomem *base) +{ + u32 reg; + int i; + + /* + * MV-S104860-U0, Rev. C: + * PCI Express Unit Soft Reset + * When set, generates an internal reset in the PCI Express unit. + * This bit should be cleared after the link is re-established. + */ + reg = readl(base + PCIE_DEBUG_CTRL); + reg |= PCIE_DEBUG_SOFT_RESET; + writel(reg, base + PCIE_DEBUG_CTRL); + + for (i = 0; i < 20; i++) { + mdelay(10); + + if (orion_pcie_link_up(base)) + break; + } + + reg &= ~(PCIE_DEBUG_SOFT_RESET); + writel(reg, base + PCIE_DEBUG_CTRL); +} + /* * Setup PCIE BARs and Address Decode Wins: * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks * WIN[0-3] -> DRAM bank[0-3] */ -static void __init orion_pcie_setup_wins(void __iomem *base, - struct mbus_dram_target_info *dram) +static void __init orion_pcie_setup_wins(void __iomem *base) { + const struct mbus_dram_target_info *dram; u32 size; int i; + dram = mv_mbus_dram_info(); + /* * First, disable and clear BARs and windows. */ @@ -120,7 +152,7 @@ static void __init orion_pcie_setup_wins(void __iomem *base, */ size = 0; for (i = 0; i < dram->num_cs; i++) { - struct mbus_dram_window *cs = dram->cs + i; + const struct mbus_dram_window *cs = dram->cs + i; writel(cs->base & 0xffff0000, base + PCIE_WIN04_BASE_OFF(i)); writel(0, base + PCIE_WIN04_REMAP_OFF(i)); @@ -133,6 +165,12 @@ static void __init orion_pcie_setup_wins(void __iomem *base, } /* + * Round up 'size' to the nearest power of two. + */ + if ((size & (size - 1)) != 0) + size = 1 << fls(size); + + /* * Setup BAR[1] to all DRAM banks. */ writel(dram->cs[0].base, base + PCIE_BAR_LO_OFF(1)); @@ -140,8 +178,7 @@ static void __init orion_pcie_setup_wins(void __iomem *base, writel(((size - 1) & 0xffff0000) | 1, base + PCIE_BAR_CTRL_OFF(1)); } -void __init orion_pcie_setup(void __iomem *base, - struct mbus_dram_target_info *dram) +void __init orion_pcie_setup(void __iomem *base) { u16 cmd; u32 mask; @@ -149,7 +186,7 @@ void __init orion_pcie_setup(void __iomem *base, /* * Point PCIe unit MBUS decode windows to DRAM space. */ - orion_pcie_setup_wins(base, dram); + orion_pcie_setup_wins(base); /* * Master + slave enable. diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c index 6fa2923e6dc..261258f717f 100644 --- a/arch/arm/plat-orion/time.c +++ b/arch/arm/plat-orion/time.c @@ -12,52 +12,61 @@ */ #include <linux/kernel.h> +#include <linux/timer.h> #include <linux/clockchips.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <asm/mach/time.h> -#include <mach/hardware.h> +#include <linux/sched_clock.h> +#include <plat/time.h> /* - * Number of timer ticks per jiffy. + * MBus bridge block registers. */ -static u32 ticks_per_jiffy; +#define BRIDGE_CAUSE_OFF 0x0110 +#define BRIDGE_MASK_OFF 0x0114 +#define BRIDGE_INT_TIMER0 0x0002 +#define BRIDGE_INT_TIMER1 0x0004 /* * Timer block registers. */ -#define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000) -#define TIMER0_EN 0x0001 -#define TIMER0_RELOAD_EN 0x0002 -#define TIMER1_EN 0x0004 -#define TIMER1_RELOAD_EN 0x0008 -#define TIMER0_RELOAD (TIMER_VIRT_BASE + 0x0010) -#define TIMER0_VAL (TIMER_VIRT_BASE + 0x0014) -#define TIMER1_RELOAD (TIMER_VIRT_BASE + 0x0018) -#define TIMER1_VAL (TIMER_VIRT_BASE + 0x001c) +#define TIMER_CTRL_OFF 0x0000 +#define TIMER0_EN 0x0001 +#define TIMER0_RELOAD_EN 0x0002 +#define TIMER1_EN 0x0004 +#define TIMER1_RELOAD_EN 0x0008 +#define TIMER0_RELOAD_OFF 0x0010 +#define TIMER0_VAL_OFF 0x0014 +#define TIMER1_RELOAD_OFF 0x0018 +#define TIMER1_VAL_OFF 0x001c /* - * Clocksource handling. + * SoC-specific data. */ -static cycle_t orion_clksrc_read(void) -{ - return 0xffffffff - readl(TIMER0_VAL); -} +static void __iomem *bridge_base; +static u32 bridge_timer1_clr_mask; +static void __iomem *timer_base; -static struct clocksource orion_clksrc = { - .name = "orion_clocksource", - .shift = 20, - .rating = 300, - .read = orion_clksrc_read, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; +/* + * Number of timer ticks per jiffy. + */ +static u32 ticks_per_jiffy; /* + * Orion's sched_clock implementation. It has a resolution of + * at least 7.5ns (133MHz TCLK). + */ + +static u64 notrace orion_read_sched_clock(void) +{ + return ~readl(timer_base + TIMER0_VAL_OFF); +} + +/* * Clockevent handling. */ static int @@ -74,23 +83,23 @@ orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev) /* * Clear and enable clockevent timer interrupt. */ - writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE); + writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); - u = readl(BRIDGE_MASK); + u = readl(bridge_base + BRIDGE_MASK_OFF); u |= BRIDGE_INT_TIMER1; - writel(u, BRIDGE_MASK); + writel(u, bridge_base + BRIDGE_MASK_OFF); /* * Setup new clockevent timer value. */ - writel(delta, TIMER1_VAL); + writel(delta, timer_base + TIMER1_VAL_OFF); /* * Enable the timer. */ - u = readl(TIMER_CTRL); + u = readl(timer_base + TIMER_CTRL_OFF); u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN; - writel(u, TIMER_CTRL); + writel(u, timer_base + TIMER_CTRL_OFF); local_irq_restore(flags); @@ -108,37 +117,38 @@ orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) /* * Setup timer to fire at 1/HZ intervals. */ - writel(ticks_per_jiffy - 1, TIMER1_RELOAD); - writel(ticks_per_jiffy - 1, TIMER1_VAL); + writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); + writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); /* * Enable timer interrupt. */ - u = readl(BRIDGE_MASK); - writel(u | BRIDGE_INT_TIMER1, BRIDGE_MASK); + u = readl(bridge_base + BRIDGE_MASK_OFF); + writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); /* * Enable timer. */ - u = readl(TIMER_CTRL); - writel(u | TIMER1_EN | TIMER1_RELOAD_EN, TIMER_CTRL); + u = readl(timer_base + TIMER_CTRL_OFF); + writel(u | TIMER1_EN | TIMER1_RELOAD_EN, + timer_base + TIMER_CTRL_OFF); } else { /* * Disable timer. */ - u = readl(TIMER_CTRL); - writel(u & ~TIMER1_EN, TIMER_CTRL); + u = readl(timer_base + TIMER_CTRL_OFF); + writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); /* * Disable timer interrupt. */ - u = readl(BRIDGE_MASK); - writel(u & ~BRIDGE_INT_TIMER1, BRIDGE_MASK); + u = readl(bridge_base + BRIDGE_MASK_OFF); + writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); /* * ACK pending timer interrupt. */ - writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE); + writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); } local_irq_restore(flags); @@ -147,7 +157,6 @@ orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) static struct clock_event_device orion_clkevt = { .name = "orion_tick", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 32, .rating = 300, .set_next_event = orion_clkevt_next_event, .set_mode = orion_clkevt_mode, @@ -158,7 +167,7 @@ static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) /* * ACK timer interrupt and call event handler. */ - writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE); + writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); orion_clkevt.event_handler(&orion_clkevt); return IRQ_HANDLED; @@ -166,38 +175,52 @@ static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) static struct irqaction orion_timer_irq = { .name = "orion_tick", - .flags = IRQF_DISABLED | IRQF_TIMER, + .flags = IRQF_TIMER, .handler = orion_timer_interrupt }; -void __init orion_time_init(unsigned int irq, unsigned int tclk) +void __init +orion_time_set_base(void __iomem *_timer_base) +{ + timer_base = _timer_base; +} + +void __init +orion_time_init(void __iomem *_bridge_base, u32 _bridge_timer1_clr_mask, + unsigned int irq, unsigned int tclk) { u32 u; + /* + * Set SoC-specific data. + */ + bridge_base = _bridge_base; + bridge_timer1_clr_mask = _bridge_timer1_clr_mask; + ticks_per_jiffy = (tclk + HZ/2) / HZ; + /* + * Set scale and timer for sched_clock. + */ + sched_clock_register(orion_read_sched_clock, 32, tclk); /* * Setup free-running clocksource timer (interrupts - * disabled.) + * disabled). */ - writel(0xffffffff, TIMER0_VAL); - writel(0xffffffff, TIMER0_RELOAD); - u = readl(BRIDGE_MASK); - writel(u & ~BRIDGE_INT_TIMER0, BRIDGE_MASK); - u = readl(TIMER_CTRL); - writel(u | TIMER0_EN | TIMER0_RELOAD_EN, TIMER_CTRL); - orion_clksrc.mult = clocksource_hz2mult(tclk, orion_clksrc.shift); - clocksource_register(&orion_clksrc); - + writel(0xffffffff, timer_base + TIMER0_VAL_OFF); + writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); + u = readl(bridge_base + BRIDGE_MASK_OFF); + writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF); + u = readl(timer_base + TIMER_CTRL_OFF); + writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF); + clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "orion_clocksource", + tclk, 300, 32, clocksource_mmio_readl_down); /* - * Setup clockevent timer (interrupt-driven.) + * Setup clockevent timer (interrupt-driven). */ setup_irq(irq, &orion_timer_irq); - orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift); - orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt); - orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt); orion_clkevt.cpumask = cpumask_of(0); - clockevents_register_device(&orion_clkevt); + clockevents_config_and_register(&orion_clkevt, tclk, 1, 0xfffffffe); } |
