mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
8
arch/arm/plat-orion/Makefile
Normal file
8
arch/arm/plat-orion/Makefile
Normal 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)
|
884
arch/arm/plat-orion/common.c
Normal file
884
arch/arm/plat-orion/common.c
Normal 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
627
arch/arm/plat-orion/gpio.c
Normal 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++;
|
||||
}
|
54
arch/arm/plat-orion/include/plat/addr-map.h
Normal file
54
arch/arm/plat-orion/include/plat/addr-map.h
Normal 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
|
113
arch/arm/plat-orion/include/plat/common.h
Normal file
113
arch/arm/plat-orion/include/plat/common.h
Normal 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
|
15
arch/arm/plat-orion/include/plat/irq.h
Normal file
15
arch/arm/plat-orion/include/plat/irq.h
Normal 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
|
34
arch/arm/plat-orion/include/plat/mpp.h
Normal file
34
arch/arm/plat-orion/include/plat/mpp.h
Normal 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
|
36
arch/arm/plat-orion/include/plat/orion-gpio.h
Normal file
36
arch/arm/plat-orion/include/plat/orion-gpio.h
Normal 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
|
34
arch/arm/plat-orion/include/plat/pcie.h
Normal file
34
arch/arm/plat-orion/include/plat/pcie.h
Normal 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
|
20
arch/arm/plat-orion/include/plat/time.h
Normal file
20
arch/arm/plat-orion/include/plat/time.h
Normal 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
40
arch/arm/plat-orion/irq.c
Normal 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
78
arch/arm/plat-orion/mpp.c
Normal 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
288
arch/arm/plat-orion/pcie.c
Normal 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
226
arch/arm/plat-orion/time.c
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue