M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
#
# Makefile for the linux kernel.
#
obj-y := irq.o pcie.o time.o common.o mpp.o addr-map.o
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_GENERIC_GPIO) += gpio.o
+174
View File
@@ -0,0 +1,174 @@
/*
* arch/arm/plat-orion/addr-map.c
*
* Address map functions for Marvell Orion based 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/module.h>
#include <linux/init.h>
#include <linux/mbus.h>
#include <linux/io.h>
#include <plat/addr-map.h>
struct mbus_dram_target_info orion_mbus_dram_info;
const struct mbus_dram_target_info *mv_mbus_dram_info(void)
{
return &orion_mbus_dram_info;
}
EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
/*
* DDR target is the same on all Orion platforms.
*/
#define TARGET_DDR 0
/*
* Helpers to get DDR bank info
*/
#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
#define DDR_SIZE_CS_OFF(n) (0x0004 + ((n) << 3))
/*
* CPU Address Decode Windows registers
*/
#define WIN_CTRL_OFF 0x0000
#define WIN_BASE_OFF 0x0004
#define WIN_REMAP_LO_OFF 0x0008
#define WIN_REMAP_HI_OFF 0x000c
/*
* Default implementation
*/
static void __init __iomem *
orion_win_cfg_base(const struct orion_addr_map_cfg *cfg, int win)
{
return (void __iomem *)(cfg->bridge_virt_base + (win << 4));
}
/*
* Default implementation
*/
static int __init orion_cpu_win_can_remap(const struct orion_addr_map_cfg *cfg,
const int win)
{
if (win < cfg->remappable_wins)
return 1;
return 0;
}
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 __iomem *addr = cfg->win_cfg_base(cfg, win);
u32 ctrl, base_high, remap_addr;
if (win >= cfg->num_wins) {
printk(KERN_ERR "setup_cpu_win: trying to allocate window "
"%d when only %d allowed\n", win, cfg->num_wins);
}
base_high = base & 0xffff0000;
ctrl = ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) | 1;
writel(base_high, addr + WIN_BASE_OFF);
writel(ctrl, addr + WIN_CTRL_OFF);
if (cfg->cpu_win_can_remap(cfg, win)) {
if (remap < 0)
remap_addr = base;
else
remap_addr = remap;
writel(remap_addr & 0xffff0000, addr + WIN_REMAP_LO_OFF);
writel(0, addr + WIN_REMAP_HI_OFF);
}
}
/*
* Configure a number of windows.
*/
static void __init orion_setup_cpu_wins(const struct orion_addr_map_cfg * cfg,
const struct orion_addr_map_info *info)
{
while (info->win != -1) {
orion_setup_cpu_win(cfg, info->win, info->base, info->size,
info->target, info->attr, info->remap);
info++;
}
}
static void __init orion_disable_wins(const struct orion_addr_map_cfg * cfg)
{
void __iomem *addr;
int i;
for (i = 0; i < cfg->num_wins; i++) {
addr = cfg->win_cfg_base(cfg, i);
writel(0, addr + WIN_BASE_OFF);
writel(0, addr + WIN_CTRL_OFF);
if (cfg->cpu_win_can_remap(cfg, i)) {
writel(0, addr + WIN_REMAP_LO_OFF);
writel(0, addr + WIN_REMAP_HI_OFF);
}
}
}
/*
* Disable, clear and configure windows.
*/
void __init orion_config_wins(struct orion_addr_map_cfg * cfg,
const struct orion_addr_map_info *info)
{
if (!cfg->cpu_win_can_remap)
cfg->cpu_win_can_remap = orion_cpu_win_can_remap;
if (!cfg->win_cfg_base)
cfg->win_cfg_base = orion_win_cfg_base;
orion_disable_wins(cfg);
if (info)
orion_setup_cpu_wins(cfg, info);
}
/*
* Setup MBUS dram target info.
*/
void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg,
const u32 ddr_window_cpu_base)
{
void __iomem *addr;
int i;
int cs;
orion_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
addr = (void __iomem *)ddr_window_cpu_base;
for (i = 0, cs = 0; i < 4; i++) {
u32 base = readl(addr + DDR_BASE_CS_OFF(i));
u32 size = readl(addr + DDR_SIZE_CS_OFF(i));
/*
* Chip select enabled?
*/
if (size & 1) {
struct mbus_dram_window *w;
w = &orion_mbus_dram_info.cs[cs++];
w->cs_index = i;
w->mbus_attr = 0xf & ~(1 << i);
w->base = base & 0xffff0000;
w->size = (size | 0x0000ffff) + 1;
}
}
orion_mbus_dram_info.num_cs = cs;
}
+936
View File
@@ -0,0 +1,936 @@
/*
* 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/mv643xx_eth.h>
#include <linux/mv643xx_i2c.h>
#include <net/dsa.h>
#include <linux/spi/orion_spi.h>
#include <plat/orion_wdt.h>
#include <plat/mv_xor.h>
#include <plat/ehci-orion.h>
#include <mach/bridge-regs.h>
/* 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 void __init uart_complete(
struct platform_device *orion_uart,
struct plat_serial8250_port *data,
struct resource *resources,
unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk)
{
data->mapbase = mapbase;
data->membase = (void __iomem *)membase;
data->irq = irq;
data->uartclk = uartclk;
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(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk)
{
uart_complete(&orion_uart0, orion_uart0_data, orion_uart0_resources,
membase, mapbase, irq, uartclk);
}
/*****************************************************************************
* 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(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk)
{
uart_complete(&orion_uart1, orion_uart1_data, orion_uart1_resources,
membase, mapbase, irq, uartclk);
}
/*****************************************************************************
* 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(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk)
{
uart_complete(&orion_uart2, orion_uart2_data, orion_uart2_resources,
membase, mapbase, irq, uartclk);
}
/*****************************************************************************
* 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(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk)
{
uart_complete(&orion_uart3, orion_uart3_data, orion_uart3_resources,
membase, mapbase, irq, uartclk);
}
/*****************************************************************************
* 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,
int tclk,
struct resource *orion_ge_resource, unsigned long irq,
struct platform_device *orion_ge_shared,
struct mv643xx_eth_platform_data *eth_data,
struct platform_device *orion_ge)
{
orion_ge_shared_data->t_clk = tclk;
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);
platform_device_register(orion_ge);
}
/*****************************************************************************
* GE00
****************************************************************************/
struct mv643xx_eth_shared_platform_data orion_ge00_shared_data;
static struct resource orion_ge00_shared_resources[] = {
{
.name = "ge00 base",
}, {
.name = "ge00 err irq",
},
};
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_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,
int tclk)
{
fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge00_shared_data, tclk,
orion_ge00_resources, irq, &orion_ge00_shared,
eth_data, &orion_ge00);
}
/*****************************************************************************
* GE01
****************************************************************************/
struct mv643xx_eth_shared_platform_data orion_ge01_shared_data = {
.shared_smi = &orion_ge00_shared,
};
static struct resource orion_ge01_shared_resources[] = {
{
.name = "ge01 base",
}, {
.name = "ge01 err irq",
},
};
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,
int tclk)
{
fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge01_shared_data, tclk,
orion_ge01_resources, irq, &orion_ge01_shared,
eth_data, &orion_ge01);
}
/*****************************************************************************
* GE10
****************************************************************************/
struct mv643xx_eth_shared_platform_data orion_ge10_shared_data = {
.shared_smi = &orion_ge00_shared,
};
static struct resource orion_ge10_shared_resources[] = {
{
.name = "ge10 base",
}, {
.name = "ge10 err irq",
},
};
static struct platform_device orion_ge10_shared = {
.name = MV643XX_ETH_SHARED_NAME,
.id = 1,
.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 = 1,
.num_resources = 2,
.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,
int tclk)
{
fill_resources(&orion_ge10_shared, orion_ge10_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge10_shared_data, tclk,
orion_ge10_resources, irq, &orion_ge10_shared,
eth_data, &orion_ge10);
}
/*****************************************************************************
* GE11
****************************************************************************/
struct mv643xx_eth_shared_platform_data orion_ge11_shared_data = {
.shared_smi = &orion_ge00_shared,
};
static struct resource orion_ge11_shared_resources[] = {
{
.name = "ge11 base",
}, {
.name = "ge11 err irq",
},
};
static struct platform_device orion_ge11_shared = {
.name = MV643XX_ETH_SHARED_NAME,
.id = 1,
.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 = 1,
.num_resources = 2,
.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,
int tclk)
{
fill_resources(&orion_ge11_shared, orion_ge11_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge11_shared_data, tclk,
orion_ge11_resources, irq, &orion_ge11_shared,
eth_data, &orion_ge11);
}
/*****************************************************************************
* Ethernet switch
****************************************************************************/
static struct resource orion_switch_resources[] = {
{
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device orion_switch_device = {
.name = "dsa",
.id = 0,
.num_resources = 0,
.resource = orion_switch_resources,
};
void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq)
{
int i;
if (irq != NO_IRQ) {
orion_switch_resources[0].start = irq;
orion_switch_resources[0].end = irq;
orion_switch_device.num_resources = 1;
}
d->netdev = &orion_ge00.dev;
for (i = 0; i < d->nr_chips; i++)
d->chip[i].mii_bus = &orion_ge00_shared.dev;
orion_switch_device.dev.platform_data = d;
platform_device_register(&orion_switch_device);
}
/*****************************************************************************
* I2C
****************************************************************************/
static struct mv64xxx_i2c_pdata orion_i2c_pdata = {
.freq_n = 3,
.timeout = 1000, /* Default timeout of 1 second */
};
static struct resource orion_i2c_resources[2];
static struct platform_device orion_i2c = {
.name = MV64XXX_I2C_CTLR_NAME,
.id = 0,
.dev = {
.platform_data = &orion_i2c_pdata,
},
};
static struct mv64xxx_i2c_pdata orion_i2c_1_pdata = {
.freq_n = 3,
.timeout = 1000, /* Default timeout of 1 second */
};
static struct resource orion_i2c_1_resources[2];
static struct platform_device orion_i2c_1 = {
.name = MV64XXX_I2C_CTLR_NAME,
.id = 1,
.dev = {
.platform_data = &orion_i2c_1_pdata,
},
};
void __init orion_i2c_init(unsigned long mapbase,
unsigned long irq,
unsigned long freq_m)
{
orion_i2c_pdata.freq_m = freq_m;
fill_resources(&orion_i2c, orion_i2c_resources, mapbase,
SZ_32 - 1, irq);
platform_device_register(&orion_i2c);
}
void __init orion_i2c_1_init(unsigned long mapbase,
unsigned long irq,
unsigned long freq_m)
{
orion_i2c_1_pdata.freq_m = freq_m;
fill_resources(&orion_i2c_1, orion_i2c_1_resources, mapbase,
SZ_32 - 1, irq);
platform_device_register(&orion_i2c_1);
}
/*****************************************************************************
* SPI
****************************************************************************/
static struct orion_spi_info orion_spi_plat_data;
static struct resource orion_spi_resources;
static struct platform_device orion_spi = {
.name = "orion_spi",
.id = 0,
.dev = {
.platform_data = &orion_spi_plat_data,
},
};
static struct orion_spi_info orion_spi_1_plat_data;
static struct resource orion_spi_1_resources;
static struct platform_device orion_spi_1 = {
.name = "orion_spi",
.id = 1,
.dev = {
.platform_data = &orion_spi_1_plat_data,
},
};
/* 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,
unsigned long tclk)
{
orion_spi_plat_data.tclk = tclk;
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,
unsigned long tclk)
{
orion_spi_1_plat_data.tclk = tclk;
fill_resources(&orion_spi_1, &orion_spi_1_resources,
mapbase, SZ_512 - 1, NO_IRQ);
platform_device_register(&orion_spi_1);
}
/*****************************************************************************
* Watchdog
****************************************************************************/
static struct orion_wdt_platform_data orion_wdt_data;
static struct resource orion_wdt_resource =
DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28);
static struct platform_device orion_wdt_device = {
.name = "orion_wdt",
.id = -1,
.dev = {
.platform_data = &orion_wdt_data,
},
.resource = &orion_wdt_resource,
.num_resources = 1,
};
void __init orion_wdt_init(unsigned long tclk)
{
orion_wdt_data.tclk = tclk;
platform_device_register(&orion_wdt_device);
}
/*****************************************************************************
* XOR
****************************************************************************/
static u64 orion_xor_dmamask = DMA_BIT_MASK(32);
void __init orion_xor_init_channels(
struct mv_xor_platform_data *orion_xor0_data,
struct platform_device *orion_xor0_channel,
struct mv_xor_platform_data *orion_xor1_data,
struct platform_device *orion_xor1_channel)
{
/*
* two engines can't do memset simultaneously, this limitation
* satisfied by removing memset support from one of the engines.
*/
dma_cap_set(DMA_MEMCPY, orion_xor0_data->cap_mask);
dma_cap_set(DMA_XOR, orion_xor0_data->cap_mask);
platform_device_register(orion_xor0_channel);
dma_cap_set(DMA_MEMCPY, orion_xor1_data->cap_mask);
dma_cap_set(DMA_MEMSET, orion_xor1_data->cap_mask);
dma_cap_set(DMA_XOR, orion_xor1_data->cap_mask);
platform_device_register(orion_xor1_channel);
}
/*****************************************************************************
* XOR0
****************************************************************************/
static struct resource orion_xor0_shared_resources[] = {
{
.name = "xor 0 low",
.flags = IORESOURCE_MEM,
}, {
.name = "xor 0 high",
.flags = IORESOURCE_MEM,
},
};
static struct platform_device orion_xor0_shared = {
.name = MV_XOR_SHARED_NAME,
.id = 0,
.num_resources = ARRAY_SIZE(orion_xor0_shared_resources),
.resource = orion_xor0_shared_resources,
};
static struct resource orion_xor00_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor00_data = {
.shared = &orion_xor0_shared,
.hw_id = 0,
.pool_size = PAGE_SIZE,
};
static struct platform_device orion_xor00_channel = {
.name = MV_XOR_NAME,
.id = 0,
.num_resources = ARRAY_SIZE(orion_xor00_resources),
.resource = orion_xor00_resources,
.dev = {
.dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor00_data,
},
};
static struct resource orion_xor01_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor01_data = {
.shared = &orion_xor0_shared,
.hw_id = 1,
.pool_size = PAGE_SIZE,
};
static struct platform_device orion_xor01_channel = {
.name = MV_XOR_NAME,
.id = 1,
.num_resources = ARRAY_SIZE(orion_xor01_resources),
.resource = orion_xor01_resources,
.dev = {
.dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor01_data,
},
};
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_xor00_resources[0].start = irq_0;
orion_xor00_resources[0].end = irq_0;
orion_xor01_resources[0].start = irq_1;
orion_xor01_resources[0].end = irq_1;
platform_device_register(&orion_xor0_shared);
orion_xor_init_channels(&orion_xor00_data, &orion_xor00_channel,
&orion_xor01_data, &orion_xor01_channel);
}
/*****************************************************************************
* XOR1
****************************************************************************/
static struct resource orion_xor1_shared_resources[] = {
{
.name = "xor 1 low",
.flags = IORESOURCE_MEM,
}, {
.name = "xor 1 high",
.flags = IORESOURCE_MEM,
},
};
static struct platform_device orion_xor1_shared = {
.name = MV_XOR_SHARED_NAME,
.id = 1,
.num_resources = ARRAY_SIZE(orion_xor1_shared_resources),
.resource = orion_xor1_shared_resources,
};
static struct resource orion_xor10_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor10_data = {
.shared = &orion_xor1_shared,
.hw_id = 0,
.pool_size = PAGE_SIZE,
};
static struct platform_device orion_xor10_channel = {
.name = MV_XOR_NAME,
.id = 2,
.num_resources = ARRAY_SIZE(orion_xor10_resources),
.resource = orion_xor10_resources,
.dev = {
.dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor10_data,
},
};
static struct resource orion_xor11_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
},
};
static struct mv_xor_platform_data orion_xor11_data = {
.shared = &orion_xor1_shared,
.hw_id = 1,
.pool_size = PAGE_SIZE,
};
static struct platform_device orion_xor11_channel = {
.name = MV_XOR_NAME,
.id = 3,
.num_resources = ARRAY_SIZE(orion_xor11_resources),
.resource = orion_xor11_resources,
.dev = {
.dma_mask = &orion_xor_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(64),
.platform_data = &orion_xor11_data,
},
};
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_xor10_resources[0].start = irq_0;
orion_xor10_resources[0].end = irq_0;
orion_xor11_resources[0].start = irq_1;
orion_xor11_resources[0].end = irq_1;
platform_device_register(&orion_xor1_shared);
orion_xor_init_channels(&orion_xor10_data, &orion_xor10_channel,
&orion_xor11_data, &orion_xor11_channel);
}
/*****************************************************************************
* 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);
}
+481
View File
@@ -0,0 +1,481 @@
/*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/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;
};
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;
}
/*
* GENERIC_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 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, 0);
__set_blinking(ochip, pin, blink);
spin_unlock_irqrestore(&ochip->lock, flags);
}
EXPORT_SYMBOL(orion_gpio_set_blink);
/*****************************************************************************
* 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->irq - gc->irq_base;
u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
if (!u) {
printk(KERN_ERR "orion gpio_irq_set_type failed "
"(irq %d, pin %d).\n", d->irq, pin);
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;
}
void __init orion_gpio_init(int gpio_base, int ngpio,
u32 base, int mask_offset, int secondary_irq_base)
{
struct orion_gpio_chip *ochip;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
char gc_label[16];
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;
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);
orion_gpio_chip_count++;
/*
* Mask and clear GPIO interrupts.
*/
writel(0, GPIO_EDGE_CAUSE(ochip));
writel(0, GPIO_EDGE_MASK(ochip));
writel(0, GPIO_LEVEL_MASK(ochip));
gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base,
ochip->base, handle_level_irq);
gc->private = ochip;
ct = gc->chip_types;
ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_set_type = gpio_irq_set_type;
ct++;
ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF;
ct->regs.ack = GPIO_EDGE_CAUSE_OFF;
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
ct->chip.irq_ack = irq_gc_ack_clr_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_set_type = gpio_irq_set_type;
ct->handler = handle_edge_irq;
irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
}
void orion_gpio_irq_handler(int pinoff)
{
struct orion_gpio_chip *ochip;
u32 cause, type;
int i;
ochip = orion_gpio_chip_find(pinoff);
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 = irqd_get_trigger_type(irq_get_irq_data(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);
}
}
@@ -0,0 +1,53 @@
/*
* 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;
const u32 bridge_virt_base;
/* 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 u32 ddr_window_cpu_base);
#endif
@@ -0,0 +1,7 @@
#ifndef __PLAT_AUDIO_H
#define __PLAT_AUDIO_H
struct kirkwood_asoc_platform_data {
int burst;
};
#endif
@@ -0,0 +1,11 @@
/*
* arch/arm/plat-orion/include/plat/cache-feroceon-l2.h
*
* Copyright (C) 2008 Marvell Semiconductor
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
extern void __init feroceon_l2_init(int l2_wt_override);
@@ -0,0 +1,109 @@
/*
* 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>
struct dsa_platform_data;
void __init orion_uart0_init(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk);
void __init orion_uart1_init(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk);
void __init orion_uart2_init(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk);
void __init orion_uart3_init(unsigned int membase,
resource_size_t mapbase,
unsigned int irq,
unsigned int uartclk);
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,
int tclk);
void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
unsigned long irq,
unsigned long irq_err,
int tclk);
void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
unsigned long irq,
unsigned long irq_err,
int tclk);
void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase,
unsigned long irq,
unsigned long irq_err,
int tclk);
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,
unsigned long tclk);
void __init orion_spi_1_init(unsigned long mapbase,
unsigned long tclk);
void __init orion_wdt_init(unsigned long tclk);
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);
#endif
@@ -0,0 +1,26 @@
/*
* arch/arm/plat-orion/include/plat/ehci-orion.h
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __PLAT_EHCI_ORION_H
#define __PLAT_EHCI_ORION_H
#include <linux/mbus.h>
enum orion_ehci_phy_ver {
EHCI_PHY_ORION,
EHCI_PHY_DD,
EHCI_PHY_KW,
EHCI_PHY_NA,
};
struct orion_ehci_data {
enum orion_ehci_phy_ver phy_version;
};
#endif
@@ -0,0 +1,37 @@
/*
* arch/arm/plat-orion/include/plat/gpio.h
*
* Marvell Orion SoC GPIO handling.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __PLAT_GPIO_H
#define __PLAT_GPIO_H
#include <linux/init.h>
#include <linux/types.h>
/*
* Orion-specific GPIO API extensions.
*/
void orion_gpio_set_unused(unsigned pin);
void orion_gpio_set_blink(unsigned pin, int blink);
#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(int gpio_base, int ngpio,
u32 base, int mask_offset, int secondary_irq_base);
/*
* GPIO interrupt handling.
*/
void orion_gpio_irq_handler(int irqoff);
#endif
@@ -0,0 +1,17 @@
/*
* 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
@@ -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, unsigned int dev_bus);
#endif
@@ -0,0 +1,24 @@
/*
* arch/arm/plat-orion/include/plat/mv_xor.h
*
* Marvell XOR platform device data definition file.
*/
#ifndef __PLAT_MV_XOR_H
#define __PLAT_MV_XOR_H
#include <linux/dmaengine.h>
#include <linux/mbus.h>
#define MV_XOR_SHARED_NAME "mv_xor_shared"
#define MV_XOR_NAME "mv_xor"
struct mv_xor_platform_data {
struct platform_device *shared;
int hw_id;
dma_cap_mask_t cap_mask;
size_t pool_size;
};
#endif
@@ -0,0 +1,20 @@
/*
* arch/arm/plat-orion/include/plat/mvsdio.h
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __MACH_MVSDIO_H
#define __MACH_MVSDIO_H
#include <linux/mbus.h>
struct mvsdio_platform_data {
unsigned int clock;
int gpio_card_detect;
int gpio_write_protect;
};
#endif
@@ -0,0 +1,26 @@
/*
* arch/arm/plat-orion/include/plat/orion_nand.h
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __PLAT_ORION_NAND_H
#define __PLAT_ORION_NAND_H
/*
* Device bus NAND private data
*/
struct orion_nand_data {
struct mtd_partition *parts;
int (*dev_ready)(struct mtd_info *mtd);
u32 nr_parts;
u8 ale; /* address line number connected to ALE */
u8 cle; /* address line number connected to CLE */
u8 width; /* buswidth */
u8 chip_delay;
};
#endif
@@ -0,0 +1,18 @@
/*
* arch/arm/plat-orion/include/plat/orion_wdt.h
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __PLAT_ORION_WDT_H
#define __PLAT_ORION_WDT_H
struct orion_wdt_platform_data {
u32 tclk; /* no <linux/clk.h> support yet */
};
#endif
@@ -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
@@ -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(u32 timer_base);
void orion_time_init(u32 bridge_base, u32 bridge_timer1_clr_mask,
unsigned int irq, unsigned int tclk);
#endif
+34
View File
@@ -0,0 +1,34 @@
/*
* 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/io.h>
#include <plat/irq.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);
}
+77
View File
@@ -0,0 +1,77 @@
/*
* 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/mpp.h>
/* Address of the ith MPP control register */
static __init unsigned long mpp_ctrl_addr(unsigned int i,
unsigned long dev_bus)
{
return dev_bus + (i) * 4;
}
void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask,
unsigned int mpp_max, unsigned int 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");
}
+286
View File
@@ -0,0 +1,286 @@
/*
* 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 __init orion_pcie_dev_id(void __iomem *base)
{
return readl(base + PCIE_DEV_ID_OFF) >> 16;
}
u32 __init 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,
struct mbus_dram_target_info *dram)
{
u32 size;
int i;
/*
* 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++) {
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, &orion_mbus_dram_info);
/*
* 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;
}
+229
View File
@@ -0,0 +1,229 @@
/*
* 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 <asm/sched_clock.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 u32 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,
.shift = 32,
.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_DISABLED | IRQF_TIMER,
.handler = orion_timer_interrupt
};
void __init
orion_time_set_base(u32 _timer_base)
{
timer_base = (void __iomem *)_timer_base;
}
void __init
orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask,
unsigned int irq, unsigned int tclk)
{
u32 u;
/*
* Set SoC-specific data.
*/
bridge_base = (void __iomem *)_bridge_base;
bridge_timer1_clr_mask = _bridge_timer1_clr_mask;
ticks_per_jiffy = (tclk + HZ/2) / HZ;
/*
* Set scale and timer for sched_clock.
*/
setup_sched_clock(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.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift);
orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt);
orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt);
orion_clkevt.cpumask = cpumask_of(0);
clockevents_register_device(&orion_clkevt);
}