Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,8 @@
#
# Makefile for the linux kernel.
#
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
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)

View file

@ -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].host_dev = &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);
}

627
arch/arm/plat-orion/gpio.c Normal file
View file

@ -0,0 +1,627 @@
/*
* arch/arm/plat-orion/gpio.c
*
* 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.
*/
#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 <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>
/*
* 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 void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip)
{
return ochip->base + GPIO_OUT_OFF;
}
static void __iomem *GPIO_IO_CONF(struct orion_gpio_chip *ochip)
{
return ochip->base + GPIO_IO_CONF_OFF;
}
static void __iomem *GPIO_BLINK_EN(struct orion_gpio_chip *ochip)
{
return ochip->base + GPIO_BLINK_EN_OFF;
}
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;
}
static void __iomem *GPIO_EDGE_CAUSE(struct orion_gpio_chip *ochip)
{
return ochip->base + GPIO_EDGE_CAUSE_OFF;
}
static void __iomem *GPIO_EDGE_MASK(struct orion_gpio_chip *ochip)
{
return ochip->base + ochip->mask_offset + GPIO_EDGE_MASK_OFF;
}
static void __iomem *GPIO_LEVEL_MASK(struct orion_gpio_chip *ochip)
{
return ochip->base + ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
}
static struct orion_gpio_chip orion_gpio_chips[2];
static int orion_gpio_chip_count;
static inline void
__set_direction(struct orion_gpio_chip *ochip, unsigned pin, int input)
{
u32 u;
u = readl(GPIO_IO_CONF(ochip));
if (input)
u |= 1 << pin;
else
u &= ~(1 << pin);
writel(u, GPIO_IO_CONF(ochip));
}
static void __set_level(struct orion_gpio_chip *ochip, unsigned pin, int high)
{
u32 u;
u = readl(GPIO_OUT(ochip));
if (high)
u |= 1 << pin;
else
u &= ~(1 << pin);
writel(u, GPIO_OUT(ochip));
}
static inline void
__set_blinking(struct orion_gpio_chip *ochip, unsigned pin, int blink)
{
u32 u;
u = readl(GPIO_BLINK_EN(ochip));
if (blink)
u |= 1 << pin;
else
u &= ~(1 << pin);
writel(u, GPIO_BLINK_EN(ochip));
}
static inline int
orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode)
{
if (pin >= ochip->chip.ngpio)
goto err_out;
if ((mode & GPIO_INPUT_OK) && !test_bit(pin, &ochip->valid_input))
goto err_out;
if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, &ochip->valid_output))
goto err_out;
return 1;
err_out:
pr_debug("%s: invalid GPIO %d\n", __func__, pin);
return false;
}
/*
* GPIO primitives.
*/
static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
{
struct orion_gpio_chip *ochip =
container_of(chip, struct orion_gpio_chip, chip);
if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) ||
orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
return 0;
return -EINVAL;
}
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;
if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK))
return -EINVAL;
spin_lock_irqsave(&ochip->lock, flags);
__set_direction(ochip, pin, 1);
spin_unlock_irqrestore(&ochip->lock, flags);
return 0;
}
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;
}
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;
if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
return -EINVAL;
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 0;
}
static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
{
struct orion_gpio_chip *ochip =
container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags;
spin_lock_irqsave(&ochip->lock, flags);
__set_level(ochip, pin, value);
spin_unlock_irqrestore(&ochip->lock, flags);
}
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)
{
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 mode)
{
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, &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;
if (ochip == NULL)
return;
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);
#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)
{
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_GPL(orion_gpio_led_blink_set);
/*****************************************************************************
* Orion GPIO IRQ
*
* GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
* value of the line or the opposite value.
*
* Level IRQ handlers: DATA_IN is used directly as cause register.
* Interrupt are masked by LEVEL_MASK registers.
* Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE.
* Interrupt are masked by EDGE_MASK registers.
* Both-edge handlers: Similar to regular Edge handlers, but also swaps
* the polarity to catch the next line transaction.
* This is a race condition that might not perfectly
* work on some use cases.
*
* Every eight GPIO lines are grouped (OR'ed) before going up to main
* cause register.
*
* EDGE cause mask
* data-in /--------| |-----| |----\
* -----| |----- ---- to main cause reg
* X \----------------| |----/
* polarity LEVEL mask
*
****************************************************************************/
static int gpio_irq_set_type(struct irq_data *d, u32 type)
{
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;
pin = d->hwirq - ochip->secondary_irq_base;
u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
if (!u) {
return -EINVAL;
}
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(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(ochip));
u |= 1 << pin;
writel(u, GPIO_IN_POL(ochip));
} else if (type == IRQ_TYPE_EDGE_BOTH) {
u32 v;
v = readl(GPIO_IN_POL(ochip)) ^ readl(GPIO_DATA_IN(ochip));
/*
* set initial polarity based on current input level
*/
u = readl(GPIO_IN_POL(ochip));
if (v & (1 << pin))
u |= 1 << pin; /* falling */
else
u &= ~(1 << pin); /* rising */
writel(u, GPIO_IN_POL(ochip));
}
return 0;
}
static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
struct orion_gpio_chip *ochip = irq_get_handler_data(irq);
u32 cause, type;
int i;
if (ochip == NULL)
return;
cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip));
cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip));
for (i = 0; i < ochip->chip.ngpio; i++) {
int irq;
irq = ochip->secondary_irq_base + i;
if (!(cause & (1 << i)))
continue;
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(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;
}
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
static void orion_gpio_unmask_irq(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
u32 reg_val;
u32 mask = d->mask;
irq_gc_lock(gc);
reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask);
reg_val |= mask;
irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask);
irq_gc_unlock(gc);
}
static void orion_gpio_mask_irq(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct irq_chip_type *ct = irq_data_get_chip_type(d);
u32 mask = d->mask;
u32 reg_val;
irq_gc_lock(gc);
reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask);
reg_val &= ~mask;
irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask);
irq_gc_unlock(gc);
}
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 = orion_gpio_mask_irq;
ct->chip.irq_unmask = orion_gpio_unmask_irq;
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 = orion_gpio_mask_irq;
ct->chip.irq_unmask = orion_gpio_unmask_irq;
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++;
}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,15 @@
/*
* arch/arm/plat-orion/include/plat/irq.h
*
* Marvell Orion SoC IRQ 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_IRQ_H
#define __PLAT_IRQ_H
void orion_irq_init(unsigned int irq_start, void __iomem *maskaddr);
#endif

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,34 @@
/*
* arch/arm/plat-orion/include/plat/pcie.h
*
* Marvell Orion SoC PCIe 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_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_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,
u32 devfn, int where, int size, u32 *val);
int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val);
int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 val);
#endif

View file

@ -0,0 +1,20 @@
/*
* arch/arm/plat-orion/include/plat/time.h
*
* Marvell Orion SoC time 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_TIME_H
#define __PLAT_TIME_H
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

40
arch/arm/plat-orion/irq.c Normal file
View file

@ -0,0 +1,40 @@
/*
* arch/arm/plat-orion/irq.c
*
* Marvell Orion SoC IRQ 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.
*/
#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>
#include <plat/orion-gpio.h>
#include <mach/bridge-regs.h>
void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
/*
* Mask all interrupts initially.
*/
writel(0, maskaddr);
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);
}

78
arch/arm/plat-orion/mpp.c Normal file
View file

@ -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");
}

288
arch/arm/plat-orion/pcie.c Normal file
View file

@ -0,0 +1,288 @@
/*
* arch/arm/plat-orion/pcie.c
*
* Marvell Orion SoC PCIe 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.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#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.
*/
#define PCIE_DEV_ID_OFF 0x0000
#define PCIE_CMD_OFF 0x0004
#define PCIE_DEV_REV_OFF 0x0008
#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
#define PCIE_HEADER_LOG_4_OFF 0x0128
#define PCIE_BAR_CTRL_OFF(n) (0x1804 + ((n - 1) * 4))
#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
#define PCIE_WIN5_CTRL_OFF 0x1880
#define PCIE_WIN5_BASE_OFF 0x1884
#define PCIE_WIN5_REMAP_OFF 0x188c
#define PCIE_CONF_ADDR_OFF 0x18f8
#define PCIE_CONF_ADDR_EN 0x80000000
#define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc))
#define PCIE_CONF_BUS(b) (((b) & 0xff) << 16)
#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11)
#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8)
#define PCIE_CONF_DATA_OFF 0x18fc
#define PCIE_MASK_OFF 0x1910
#define PCIE_CTRL_OFF 0x1a00
#define PCIE_CTRL_X1_MODE 0x0001
#define PCIE_STAT_OFF 0x1a04
#define PCIE_STAT_DEV_OFFS 20
#define PCIE_STAT_DEV_MASK 0x1f
#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 orion_pcie_dev_id(void __iomem *base)
{
return readl(base + PCIE_DEV_ID_OFF) >> 16;
}
u32 orion_pcie_rev(void __iomem *base)
{
return readl(base + PCIE_DEV_REV_OFF) & 0xff;
}
int orion_pcie_link_up(void __iomem *base)
{
return !(readl(base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
}
int __init orion_pcie_x4_mode(void __iomem *base)
{
return !(readl(base + PCIE_CTRL_OFF) & PCIE_CTRL_X1_MODE);
}
int orion_pcie_get_local_bus_nr(void __iomem *base)
{
u32 stat = readl(base + PCIE_STAT_OFF);
return (stat >> PCIE_STAT_BUS_OFFS) & PCIE_STAT_BUS_MASK;
}
void __init orion_pcie_set_local_bus_nr(void __iomem *base, int nr)
{
u32 stat;
stat = readl(base + PCIE_STAT_OFF);
stat &= ~(PCIE_STAT_BUS_MASK << PCIE_STAT_BUS_OFFS);
stat |= nr << PCIE_STAT_BUS_OFFS;
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)
{
const struct mbus_dram_target_info *dram;
u32 size;
int i;
dram = mv_mbus_dram_info();
/*
* First, disable and clear BARs and windows.
*/
for (i = 1; i <= 2; i++) {
writel(0, base + PCIE_BAR_CTRL_OFF(i));
writel(0, base + PCIE_BAR_LO_OFF(i));
writel(0, base + PCIE_BAR_HI_OFF(i));
}
for (i = 0; i < 5; i++) {
writel(0, base + PCIE_WIN04_CTRL_OFF(i));
writel(0, base + PCIE_WIN04_BASE_OFF(i));
writel(0, base + PCIE_WIN04_REMAP_OFF(i));
}
writel(0, base + PCIE_WIN5_CTRL_OFF);
writel(0, base + PCIE_WIN5_BASE_OFF);
writel(0, base + PCIE_WIN5_REMAP_OFF);
/*
* Setup windows for DDR banks. Count total DDR size on the fly.
*/
size = 0;
for (i = 0; i < dram->num_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));
writel(((cs->size - 1) & 0xffff0000) |
(cs->mbus_attr << 8) |
(dram->mbus_dram_target_id << 4) | 1,
base + PCIE_WIN04_CTRL_OFF(i));
size += cs->size;
}
/*
* 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));
writel(0, base + PCIE_BAR_HI_OFF(1));
writel(((size - 1) & 0xffff0000) | 1, base + PCIE_BAR_CTRL_OFF(1));
}
void __init orion_pcie_setup(void __iomem *base)
{
u16 cmd;
u32 mask;
/*
* Point PCIe unit MBUS decode windows to DRAM space.
*/
orion_pcie_setup_wins(base);
/*
* Master + slave enable.
*/
cmd = readw(base + PCIE_CMD_OFF);
cmd |= PCI_COMMAND_IO;
cmd |= PCI_COMMAND_MEMORY;
cmd |= PCI_COMMAND_MASTER;
writew(cmd, base + PCIE_CMD_OFF);
/*
* Enable interrupt lines A-D.
*/
mask = readl(base + PCIE_MASK_OFF);
mask |= 0x0f000000;
writel(mask, base + PCIE_MASK_OFF);
}
int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val)
{
writel(PCIE_CONF_BUS(bus->number) |
PCIE_CONF_DEV(PCI_SLOT(devfn)) |
PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
base + PCIE_CONF_ADDR_OFF);
*val = readl(base + PCIE_CONF_DATA_OFF);
if (size == 1)
*val = (*val >> (8 * (where & 3))) & 0xff;
else if (size == 2)
*val = (*val >> (8 * (where & 3))) & 0xffff;
return PCIBIOS_SUCCESSFUL;
}
int orion_pcie_rd_conf_tlp(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val)
{
writel(PCIE_CONF_BUS(bus->number) |
PCIE_CONF_DEV(PCI_SLOT(devfn)) |
PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
base + PCIE_CONF_ADDR_OFF);
*val = readl(base + PCIE_CONF_DATA_OFF);
if (bus->number != orion_pcie_get_local_bus_nr(base) ||
PCI_FUNC(devfn) != 0)
*val = readl(base + PCIE_HEADER_LOG_4_OFF);
if (size == 1)
*val = (*val >> (8 * (where & 3))) & 0xff;
else if (size == 2)
*val = (*val >> (8 * (where & 3))) & 0xffff;
return PCIBIOS_SUCCESSFUL;
}
int orion_pcie_rd_conf_wa(void __iomem *wa_base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 *val)
{
*val = readl(wa_base + (PCIE_CONF_BUS(bus->number) |
PCIE_CONF_DEV(PCI_SLOT(devfn)) |
PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
PCIE_CONF_REG(where)));
if (size == 1)
*val = (*val >> (8 * (where & 3))) & 0xff;
else if (size == 2)
*val = (*val >> (8 * (where & 3))) & 0xffff;
return PCIBIOS_SUCCESSFUL;
}
int orion_pcie_wr_conf(void __iomem *base, struct pci_bus *bus,
u32 devfn, int where, int size, u32 val)
{
int ret = PCIBIOS_SUCCESSFUL;
writel(PCIE_CONF_BUS(bus->number) |
PCIE_CONF_DEV(PCI_SLOT(devfn)) |
PCIE_CONF_FUNC(PCI_FUNC(devfn)) |
PCIE_CONF_REG(where) | PCIE_CONF_ADDR_EN,
base + PCIE_CONF_ADDR_OFF);
if (size == 4) {
writel(val, base + PCIE_CONF_DATA_OFF);
} else if (size == 2) {
writew(val, base + PCIE_CONF_DATA_OFF + (where & 3));
} else if (size == 1) {
writeb(val, base + PCIE_CONF_DATA_OFF + (where & 3));
} else {
ret = PCIBIOS_BAD_REGISTER_NUMBER;
}
return ret;
}

226
arch/arm/plat-orion/time.c Normal file
View file

@ -0,0 +1,226 @@
/*
* arch/arm/plat-orion/time.c
*
* Marvell Orion SoC timer 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.
*
* Timer 0 is used as free-running clocksource, while timer 1 is
* used as clock_event_device.
*/
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched_clock.h>
#include <plat/time.h>
/*
* MBus bridge block registers.
*/
#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_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
/*
* SoC-specific data.
*/
static void __iomem *bridge_base;
static u32 bridge_timer1_clr_mask;
static void __iomem *timer_base;
/*
* 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
orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
{
unsigned long flags;
u32 u;
if (delta == 0)
return -ETIME;
local_irq_save(flags);
/*
* Clear and enable clockevent timer interrupt.
*/
writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF);
u = readl(bridge_base + BRIDGE_MASK_OFF);
u |= BRIDGE_INT_TIMER1;
writel(u, bridge_base + BRIDGE_MASK_OFF);
/*
* Setup new clockevent timer value.
*/
writel(delta, timer_base + TIMER1_VAL_OFF);
/*
* Enable the timer.
*/
u = readl(timer_base + TIMER_CTRL_OFF);
u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN;
writel(u, timer_base + TIMER_CTRL_OFF);
local_irq_restore(flags);
return 0;
}
static void
orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
unsigned long flags;
u32 u;
local_irq_save(flags);
if (mode == CLOCK_EVT_MODE_PERIODIC) {
/*
* Setup timer to fire at 1/HZ intervals.
*/
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_base + BRIDGE_MASK_OFF);
writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF);
/*
* Enable timer.
*/
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_base + TIMER_CTRL_OFF);
writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF);
/*
* Disable timer interrupt.
*/
u = readl(bridge_base + BRIDGE_MASK_OFF);
writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF);
/*
* ACK pending timer interrupt.
*/
writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF);
}
local_irq_restore(flags);
}
static struct clock_event_device orion_clkevt = {
.name = "orion_tick",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.rating = 300,
.set_next_event = orion_clkevt_next_event,
.set_mode = orion_clkevt_mode,
};
static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
{
/*
* ACK timer interrupt and call event handler.
*/
writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF);
orion_clkevt.event_handler(&orion_clkevt);
return IRQ_HANDLED;
}
static struct irqaction orion_timer_irq = {
.name = "orion_tick",
.flags = IRQF_TIMER,
.handler = orion_timer_interrupt
};
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).
*/
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_irq(irq, &orion_timer_irq);
orion_clkevt.cpumask = cpumask_of(0);
clockevents_config_and_register(&orion_clkevt, tclk, 1, 0xfffffffe);
}