提交 49cbe786 编写于 作者: E Eric Miao

[ARM] pxa: add base support for Marvell's PXA168 processor line

"""The Marvell® PXA168 processor is the first in a family of application
processors targeted at mass market opportunities in computing and consumer
devices. It balances high computing and multimedia performance with low
power consumption to support extended battery life, and includes a wealth
of integrated peripherals to reduce overall BOM cost .... """

See http://www.marvell.com/featured/pxa168.jsp for more information.

  1. Marvell Mohawk core is a hybrid of xscale3 and its own ARM core,
     there are many enhancements like instructions for flushing the
     whole D-cache, and so on

  2. Clock reuses Russell's common clkdev, and added the basic support
     for UART1/2.

  3. Devices are a bit different from the 'mach-pxa' way, the platform
     devices are now dynamically allocated only when necessary (i.e.
     when pxa_register_device() is called). Description for each device
     are stored in an array of 'struct pxa_device_desc'. Now that:

     a. this array of device description is marked with __initdata and
        can be freed up system is fully up

     b. which means board code has to add all needed devices early in
        his initializing function

     c. platform specific data can now be marked as __initdata since
        they are allocated and copied by platform_device_add_data()

  4. only the basic UART1/2/3 are added, more devices will come later.
Signed-off-by: NJason Chagas <chagas@marvell.com>
Signed-off-by: NEric Miao <eric.miao@marvell.com>
上级 f8dec04d
......@@ -478,6 +478,8 @@ config ARCH_PXA
select HAVE_CLK
select COMMON_CLKDEV
select ARCH_REQUIRE_GPIOLIB
select HAVE_CLK
select COMMON_CLKDEV
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select TICK_ONESHOT
......@@ -485,6 +487,18 @@ config ARCH_PXA
help
Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
config ARCH_MMP
bool "Marvell PXA168"
depends on MMU
select HAVE_CLK
select COMMON_CLKDEV
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select TICK_ONESHOT
select PLAT_PXA
help
Support for Marvell's PXA168 processor line.
config ARCH_RPC
bool "RiscPC"
select ARCH_ACORN
......@@ -621,6 +635,8 @@ source "arch/arm/mach-mv78xx0/Kconfig"
source "arch/arm/mach-pxa/Kconfig"
source "arch/arm/plat-pxa/Kconfig"
source "arch/arm/mach-mmp/Kconfig"
source "arch/arm/mach-sa1100/Kconfig"
source "arch/arm/plat-omap/Kconfig"
......
......@@ -109,6 +109,7 @@ ifeq ($(CONFIG_ARCH_SA1100),y)
textofs-$(CONFIG_SA1111) := 0x00208000
endif
machine-$(CONFIG_ARCH_PXA) := pxa
machine-$(CONFIG_ARCH_MMP) := mmp
plat-$(CONFIG_PLAT_PXA) := pxa
machine-$(CONFIG_ARCH_L7200) := l7200
machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
......
......@@ -636,6 +636,18 @@ proc_types:
b __armv4_mmu_cache_off
b __armv4_mmu_cache_flush
.word 0x56158000 @ PXA168
.word 0xfffff000
b __armv4_mmu_cache_on
b __armv4_mmu_cache_off
b __armv5tej_mmu_cache_flush
.word 0x56056930
.word 0xff0ffff0 @ PXA935
b __armv4_mmu_cache_on
b __armv4_mmu_cache_off
b __armv4_mmu_cache_flush
.word 0x56050000 @ Feroceon
.word 0xff0f0000
b __armv4_mmu_cache_on
......
......@@ -94,6 +94,14 @@
# endif
#endif
#if defined(CONFIG_CPU_MOHAWK)
# ifdef _CACHE
# define MULTI_CACHE 1
# else
# define _CACHE mohawk
# endif
#endif
#if defined(CONFIG_CPU_FEROCEON)
# define MULTI_CACHE 1
#endif
......
......@@ -185,6 +185,14 @@
# define CPU_NAME cpu_xsc3
# endif
# endif
# ifdef CONFIG_CPU_MOHAWK
# ifdef CPU_NAME
# undef MULTI_CPU
# define MULTI_CPU
# else
# define CPU_NAME cpu_mohawk
# endif
# endif
# ifdef CONFIG_CPU_FEROCEON
# ifdef CPU_NAME
# undef MULTI_CPU
......
if ARCH_MMP
menu "Marvell PXA168 Implmentations"
config MACH_ASPENITE
bool "Marvell's PXA168 Aspenite Development Board"
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
Aspenite Development Board.
config MACH_ZYLONITE2
bool "Marvell's PXA168 Zylonite2 Development Board"
select CPU_PXA168
help
Say 'Y' here if you want to support the Marvell PXA168-based
Zylonite2 Development Board.
endmenu
config CPU_PXA168
bool
select CPU_MOHAWK
help
Select code specific to PXA168
endif
#
# Makefile for Marvell's PXA168 processors line
#
obj-y += common.o clock.o devices.o irq.o time.o
# SoC support
obj-$(CONFIG_CPU_PXA168) += pxa168.o
# board support
obj-$(CONFIG_MACH_ASPENITE) += aspenite.o
obj-$(CONFIG_MACH_ZYLONITE2) += aspenite.o
zreladdr-y := 0x00008000
/*
* linux/arch/arm/mach-mmp/aspenite.c
*
* Support for the Marvell PXA168-based Aspenite and Zylonite2
* Development Platform.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* publishhed by the Free Software Foundation.
*/
#include <linux/init.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/addr-map.h>
#include "common.h"
static void __init common_init(void)
{
}
MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
.phys_io = APB_PHYS_BASE,
.boot_params = 0x00000100,
.io_pg_offst = (APB_VIRT_BASE >> 18) & 0xfffc,
.map_io = pxa_map_io,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = common_init,
MACHINE_END
MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform")
.phys_io = APB_PHYS_BASE,
.boot_params = 0x00000100,
.io_pg_offst = (APB_VIRT_BASE >> 18) & 0xfffc,
.map_io = pxa_map_io,
.init_irq = pxa168_init_irq,
.timer = &pxa168_timer,
.init_machine = common_init,
MACHINE_END
/*
* linux/arch/arm/mach-mmp/clock.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <mach/regs-apbc.h>
#include "clock.h"
static void apbc_clk_enable(struct clk *clk)
{
uint32_t clk_rst;
clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(clk->fnclksel);
__raw_writel(clk_rst, clk->clk_rst);
}
static void apbc_clk_disable(struct clk *clk)
{
__raw_writel(0, clk->clk_rst);
}
struct clkops apbc_clk_ops = {
.enable = apbc_clk_enable,
.disable = apbc_clk_disable,
};
static DEFINE_SPINLOCK(clocks_lock);
int clk_enable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clocks_lock, flags);
if (clk->enabled++ == 0)
clk->ops->enable(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
unsigned long flags;
WARN_ON(clk->enabled == 0);
spin_lock_irqsave(&clocks_lock, flags);
if (--clk->enabled == 0)
clk->ops->disable(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long rate;
if (clk->ops->getrate)
rate = clk->ops->getrate(clk);
else
rate = clk->rate;
return rate;
}
EXPORT_SYMBOL(clk_get_rate);
void clks_register(struct clk_lookup *clks, size_t num)
{
int i;
for (i = 0; i < num; i++)
clkdev_add(&clks[i]);
}
/*
* linux/arch/arm/mach-mmp/clock.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <asm/clkdev.h>
struct clkops {
void (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*getrate)(struct clk *);
};
struct clk {
const struct clkops *ops;
void __iomem *clk_rst; /* clock reset control register */
int fnclksel; /* functional clock select (APBC) */
uint32_t enable_val; /* value for clock enable (APMU) */
unsigned long rate;
int enabled;
};
extern struct clkops apbc_clk_ops;
#define APBC_CLK(_name, _reg, _fnclksel, _rate) \
struct clk clk_##_name = { \
.clk_rst = (void __iomem *)APBC_##_reg, \
.fnclksel = _fnclksel, \
.rate = _rate, \
.ops = &apbc_clk_ops, \
}
#define APBC_CLK_OPS(_name, _reg, _fnclksel, _rate, _ops) \
struct clk clk_##_name = { \
.clk_rst = (void __iomem *)APBC_##_reg, \
.fnclksel = _fnclksel, \
.rate = _rate, \
.ops = _ops, \
}
#define APMU_CLK(_name, _reg, _eval, _rate) \
struct clk clk_##_name = { \
.clk_rst = (void __iomem *)APMU_##_reg, \
.enable_val = _eval, \
.rate = _rate, \
.ops = &apmu_clk_ops, \
}
#define APMU_CLK_OPS(_name, _reg, _eval, _rate, _ops) \
struct clk clk_##_name = { \
.clk_rst = (void __iomem *)APMU_##_reg, \
.enable_val = _eval, \
.rate = _rate, \
.ops = _ops, \
}
#define INIT_CLKREG(_clk, _devname, _conname) \
{ \
.clk = _clk, \
.dev_id = _devname, \
.con_id = _conname, \
}
extern struct clk clk_pxa168_gpio;
extern struct clk clk_pxa168_timers;
extern void clks_register(struct clk_lookup *, size_t);
/*
* linux/arch/arm/mach-mmp/common.c
*
* Code common to PXA168 processor lines
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <mach/addr-map.h>
#include "common.h"
static struct map_desc standard_io_desc[] __initdata = {
{
.pfn = __phys_to_pfn(APB_PHYS_BASE),
.virtual = APB_VIRT_BASE,
.length = APB_PHYS_SIZE,
.type = MT_DEVICE,
}, {
.pfn = __phys_to_pfn(AXI_PHYS_BASE),
.virtual = AXI_VIRT_BASE,
.length = AXI_PHYS_SIZE,
.type = MT_DEVICE,
},
};
void __init pxa_map_io(void)
{
iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
}
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
struct sys_timer;
extern void timer_init(int irq);
extern struct sys_timer pxa168_timer;
extern void __init pxa168_init_irq(void);
extern void __init icu_init_irq(void);
extern void __init pxa_map_io(void);
/*
* linux/arch/arm/mach-mmp/devices.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <asm/irq.h>
#include <mach/devices.h>
int __init pxa_register_device(struct pxa_device_desc *desc,
void *data, size_t size)
{
struct platform_device *pdev;
struct resource res[2 + MAX_RESOURCE_DMA];
int i, ret = 0, nres = 0;
pdev = platform_device_alloc(desc->drv_name, desc->id);
if (pdev == NULL)
return -ENOMEM;
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
memset(res, 0, sizeof(res));
if (desc->start != -1ul && desc->size > 0) {
res[nres].start = desc->start;
res[nres].end = desc->start + desc->size - 1;
res[nres].flags = IORESOURCE_MEM;
nres++;
}
if (desc->irq != NO_IRQ) {
res[nres].start = desc->irq;
res[nres].end = desc->irq;
res[nres].flags = IORESOURCE_IRQ;
nres++;
}
for (i = 0; i < MAX_RESOURCE_DMA; i++, nres++) {
if (desc->dma[i] == 0)
break;
res[nres].start = desc->dma[i];
res[nres].end = desc->dma[i];
res[nres].flags = IORESOURCE_DMA;
}
ret = platform_device_add_resources(pdev, res, nres);
if (ret) {
platform_device_put(pdev);
return ret;
}
if (data && size) {
ret = platform_device_add_data(pdev, data, size);
if (ret) {
platform_device_put(pdev);
return ret;
}
}
return platform_device_add(pdev);
}
/*
* linux/arch/arm/mach-mmp/include/mach/addr-map.h
*
* Common address map definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_ADDR_MAP_H
#define __ASM_MACH_ADDR_MAP_H
/* APB - Application Subsystem Peripheral Bus
*
* NOTE: the DMA controller registers are actually on the AXI fabric #1
* slave port to AHB/APB bridge, due to its close relationship to those
* peripherals on APB, let's count it into the ABP mapping area.
*/
#define APB_PHYS_BASE 0xd4000000
#define APB_VIRT_BASE 0xfe000000
#define APB_PHYS_SIZE 0x00200000
#define AXI_PHYS_BASE 0xd4200000
#define AXI_VIRT_BASE 0xfe200000
#define AXI_PHYS_SIZE 0x00200000
/* Static Memory Controller - Chip Select 0 and 1 */
#define SMC_CS0_PHYS_BASE 0x80000000
#define SMC_CS0_PHYS_SIZE 0x10000000
#define SMC_CS1_PHYS_BASE 0x90000000
#define SMC_CS1_PHYS_SIZE 0x10000000
#endif /* __ASM_MACH_ADDR_MAP_H */
#ifndef __ASM_MACH_CLKDEV_H
#define __ASM_MACH_CLKDEV_H
#define __clk_get(clk) ({ 1; })
#define __clk_put(clk) do { } while (0)
#endif /* __ASM_MACH_CLKDEV_H */
#ifndef __ASM_MACH_CPUTYPE_H
#define __ASM_MACH_CPUTYPE_H
#include <asm/cputype.h>
/*
* CPU Stepping OLD_ID CPU_ID CHIP_ID
*
* PXA168 A0 0x41159263 0x56158400 0x00A0A333
*/
#ifdef CONFIG_CPU_PXA168
# define __cpu_is_pxa168(id) \
({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x84; })
#else
# define __cpu_is_pxa168(id) (0)
#endif
#define cpu_is_pxa168() ({ __cpu_is_pxa168(read_cpuid_id()); })
#endif /* __ASM_MACH_CPUTYPE_H */
/* arch/arm/mach-mmp/include/mach/debug-macro.S
*
* Debugging macro include header
*
* Copied from arch/arm/mach-pxa/include/mach/debug.S
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <mach/addr-map.h>
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
ldreq \rx, =APB_PHYS_BASE @ physical
ldrne \rx, =APB_VIRT_BASE @ virtual
orr \rx, \rx, #0x00017000
.endm
#define UART_SHIFT 2
#include <asm/hardware/debug-8250.S>
#include <linux/types.h>
#define MAX_RESOURCE_DMA 2
/* structure for describing the on-chip devices */
struct pxa_device_desc {
const char *dev_name;
const char *drv_name;
int id;
int irq;
unsigned long start;
unsigned long size;
int dma[MAX_RESOURCE_DMA];
};
#define PXA168_DEVICE(_name, _drv, _id, _irq, _start, _size, _dma...) \
struct pxa_device_desc pxa168_device_##_name __initdata = { \
.dev_name = "pxa168-" #_name, \
.drv_name = _drv, \
.id = _id, \
.irq = IRQ_PXA168_##_irq, \
.start = _start, \
.size = _size, \
.dma = { _dma }, \
};
extern int pxa_register_device(struct pxa_device_desc *, void *, size_t);
/*
* linux/arch/arm/mach-mmp/include/mach/dma.h
*/
#ifndef __ASM_MACH_DMA_H
#define __ASM_MACH_DMA_H
#include <mach/addr-map.h>
#define DMAC_REGS_VIRT (APB_VIRT_BASE + 0x00000)
#include <plat/dma.h>
#endif /* __ASM_MACH_DMA_H */
/*
* linux/arch/arm/mach-mmp/include/mach/entry-macro.S
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <mach/regs-icu.h>
.macro disable_fiq
.endm
.macro arch_ret_to_user, tmp1, tmp2
.endm
.macro get_irqnr_preamble, base, tmp
ldr \base, =ICU_AP_IRQ_SEL_INT_NUM
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
ldr \tmp, [\base, #0]
and \irqnr, \tmp, #0x3f
tst \tmp, #(1 << 6)
.endm
#ifndef __ASM_MACH_HARDWARE_H
#define __ASM_MACH_HARDWARE_H
#endif /* __ASM_MACH_HARDWARE_H */
/*
* linux/arch/arm/mach-mmp/include/mach/io.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_IO_H
#define __ASM_MACH_IO_H
#define IO_SPACE_LIMIT 0xffffffff
/*
* We don't actually have real ISA nor PCI buses, but there is so many
* drivers out there that might just work if we fake them...
*/
#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)
#endif /* __ASM_MACH_IO_H */
#ifndef __ASM_MACH_IRQS_H
#define __ASM_MACH_IRQS_H
/*
* Interrupt numbers for PXA168
*/
#define IRQ_PXA168_NONE (-1)
#define IRQ_PXA168_SSP3 0
#define IRQ_PXA168_SSP2 1
#define IRQ_PXA168_SSP1 2
#define IRQ_PXA168_SSP0 3
#define IRQ_PXA168_PMIC_INT 4
#define IRQ_PXA168_RTC_INT 5
#define IRQ_PXA168_RTC_ALARM 6
#define IRQ_PXA168_TWSI0 7
#define IRQ_PXA168_GPU 8
#define IRQ_PXA168_KEYPAD 9
#define IRQ_PXA168_ONEWIRE 12
#define IRQ_PXA168_TIMER1 13
#define IRQ_PXA168_TIMER2 14
#define IRQ_PXA168_TIMER3 15
#define IRQ_PXA168_CMU 16
#define IRQ_PXA168_SSP4 17
#define IRQ_PXA168_MSP_WAKEUP 19
#define IRQ_PXA168_CF_WAKEUP 20
#define IRQ_PXA168_XD_WAKEUP 21
#define IRQ_PXA168_MFU 22
#define IRQ_PXA168_MSP 23
#define IRQ_PXA168_CF 24
#define IRQ_PXA168_XD 25
#define IRQ_PXA168_DDR_INT 26
#define IRQ_PXA168_UART1 27
#define IRQ_PXA168_UART2 28
#define IRQ_PXA168_WDT 35
#define IRQ_PXA168_FRQ_CHANGE 38
#define IRQ_PXA168_SDH1 39
#define IRQ_PXA168_SDH2 40
#define IRQ_PXA168_LCD 41
#define IRQ_PXA168_CI 42
#define IRQ_PXA168_USB1 44
#define IRQ_PXA168_NAND 45
#define IRQ_PXA168_HIFI_DMA 46
#define IRQ_PXA168_DMA_INT0 47
#define IRQ_PXA168_DMA_INT1 48
#define IRQ_PXA168_GPIOX 49
#define IRQ_PXA168_USB2 51
#define IRQ_PXA168_AC97 57
#define IRQ_PXA168_TWSI1 58
#define IRQ_PXA168_PMU 60
#define IRQ_PXA168_SM_INT 63
#define IRQ_GPIO_START 64
#define IRQ_GPIO_NUM 128
#define IRQ_GPIO(x) (IRQ_GPIO_START + (x))
#define NR_IRQS (IRQ_GPIO_START + IRQ_GPIO_NUM)
#endif /* __ASM_MACH_IRQS_H */
/*
* linux/arch/arm/mach-mmp/include/mach/memory.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_MEMORY_H
#define __ASM_MACH_MEMORY_H
#define PHYS_OFFSET UL(0x00000000)
#endif /* __ASM_MACH_MEMORY_H */
#ifndef __ASM_MACH_PXA168_H
#define __ASM_MACH_PXA168_H
#include <mach/devices.h>
extern struct pxa_device_desc pxa168_device_uart1;
extern struct pxa_device_desc pxa168_device_uart2;
static inline int pxa168_add_uart(int id)
{
struct pxa_device_desc *d = NULL;
switch (id) {
case 1: d = &pxa168_device_uart1; break;
case 2: d = &pxa168_device_uart2; break;
}
if (d == NULL)
return -EINVAL;
return pxa_register_device(d, NULL, 0);
}
#endif /* __ASM_MACH_PXA168_H */
/*
* linux/arch/arm/mach-mmp/include/mach/regs-apbc.h
*
* Application Peripheral Bus Clock Unit
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_REGS_APBC_H
#define __ASM_MACH_REGS_APBC_H
#include <mach/addr-map.h>
#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000)
#define APBC_REG(x) (APBC_VIRT_BASE + (x))
/*
* APB clock register offsets for PXA168
*/
#define APBC_PXA168_UART1 APBC_REG(0x000)
#define APBC_PXA168_UART2 APBC_REG(0x004)
#define APBC_PXA168_GPIO APBC_REG(0x008)
#define APBC_PXA168_PWM0 APBC_REG(0x00c)
#define APBC_PXA168_PWM1 APBC_REG(0x010)
#define APBC_PXA168_SSP1 APBC_REG(0x01c)
#define APBC_PXA168_SSP2 APBC_REG(0x020)
#define APBC_PXA168_RTC APBC_REG(0x028)
#define APBC_PXA168_TWSI0 APBC_REG(0x02c)
#define APBC_PXA168_KPC APBC_REG(0x030)
#define APBC_PXA168_TIMERS APBC_REG(0x034)
#define APBC_PXA168_AIB APBC_REG(0x03c)
#define APBC_PXA168_SW_JTAG APBC_REG(0x040)
#define APBC_PXA168_ONEWIRE APBC_REG(0x048)
#define APBC_PXA168_SSP3 APBC_REG(0x04c)
#define APBC_PXA168_ASFAR APBC_REG(0x050)
#define APBC_PXA168_ASSAR APBC_REG(0x054)
#define APBC_PXA168_SSP4 APBC_REG(0x058)
#define APBC_PXA168_SSP5 APBC_REG(0x05c)
#define APBC_PXA168_TWSI1 APBC_REG(0x06c)
#define APBC_PXA168_UART3 APBC_REG(0x070)
#define APBC_PXA168_AC97 APBC_REG(0x084)
/* Common APB clock register bit definitions */
#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
#define APBC_RST (1 << 2) /* Reset Generation */
/* Functional Clock Selection Mask */
#define APBC_FNCLKSEL(x) (((x) & 0xf) << 4)
#endif /* __ASM_MACH_REGS_APBC_H */
/*
* linux/arch/arm/mach-mmp/include/mach/regs-apmu.h
*
* Application Subsystem Power Management Unit
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_REGS_APMU_H
#define __ASM_MACH_REGS_APMU_H
#include <mach/addr-map.h>
#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800)
#define APMU_REG(x) (APMU_VIRT_BASE + (x))
/* Clock Reset Control */
#define APMU_IRE APMU_REG(0x048)
#define APMU_LCD APMU_REG(0x04c)
#define APMU_CCIC APMU_REG(0x050)
#define APMU_SDH0 APMU_REG(0x054)
#define APMU_SDH1 APMU_REG(0x058)
#define APMU_USB APMU_REG(0x05c)
#define APMU_NAND APMU_REG(0x060)
#define APMU_DMA APMU_REG(0x064)
#define APMU_GEU APMU_REG(0x068)
#define APMU_BUS APMU_REG(0x06c)
#define APMU_FNCLK_EN (1 << 4)
#define APMU_AXICLK_EN (1 << 3)
#define APMU_FNRST_DIS (1 << 1)
#define APMU_AXIRST_DIS (1 << 0)
#endif /* __ASM_MACH_REGS_APMU_H */
/*
* linux/arch/arm/mach-mmp/include/mach/regs-icu.h
*
* Interrupt Control Unit
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_ICU_H
#define __ASM_MACH_ICU_H
#include <mach/addr-map.h>
#define ICU_VIRT_BASE (AXI_VIRT_BASE + 0x82000)
#define ICU_REG(x) (ICU_VIRT_BASE + (x))
#define ICU_INT_CONF(n) ICU_REG((n) << 2)
#define ICU_INT_CONF_AP_INT (1 << 6)
#define ICU_INT_CONF_CP_INT (1 << 5)
#define ICU_INT_CONF_IRQ (1 << 4)
#define ICU_INT_CONF_MASK (0xf)
#define ICU_AP_FIQ_SEL_INT_NUM ICU_REG(0x108) /* AP FIQ Selected Interrupt */
#define ICU_AP_IRQ_SEL_INT_NUM ICU_REG(0x10C) /* AP IRQ Selected Interrupt */
#define ICU_AP_GBL_IRQ_MSK ICU_REG(0x114) /* AP Global Interrupt Mask */
#define ICU_INT_STATUS_0 ICU_REG(0x128) /* Interrupt Stuats 0 */
#define ICU_INT_STATUS_1 ICU_REG(0x12C) /* Interrupt Status 1 */
#endif /* __ASM_MACH_ICU_H */
/*
* linux/arch/arm/mach-mmp/include/mach/regs-timers.h
*
* Timers Module
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_REGS_TIMERS_H
#define __ASM_MACH_REGS_TIMERS_H
#include <mach/addr-map.h>
#define TIMERS1_VIRT_BASE (APB_VIRT_BASE + 0x14000)
#define TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x16000)
#define TMR_CCR (0x0000)
#define TMR_TN_MM(n, m) (0x0004 + ((n) << 3) + (((n) + (m)) << 2))
#define TMR_CR(n) (0x0028 + ((n) << 2))
#define TMR_SR(n) (0x0034 + ((n) << 2))
#define TMR_IER(n) (0x0040 + ((n) << 2))
#define TMR_PLVR(n) (0x004c + ((n) << 2))
#define TMR_PLCR(n) (0x0058 + ((n) << 2))
#define TMR_WMER (0x0064)
#define TMR_WMR (0x0068)
#define TMR_WVR (0x006c)
#define TMR_WSR (0x0070)
#define TMR_ICR(n) (0x0074 + ((n) << 2))
#define TMR_WICR (0x0080)
#define TMR_CER (0x0084)
#define TMR_CMR (0x0088)
#define TMR_ILR(n) (0x008c + ((n) << 2))
#define TMR_WCR (0x0098)
#define TMR_WFAR (0x009c)
#define TMR_WSAR (0x00A0)
#define TMR_CVWR(n) (0x00A4 + ((n) << 2))
#define TMR_CCR_CS_0(x) (((x) & 0x3) << 0)
#define TMR_CCR_CS_1(x) (((x) & 0x7) << 2)
#define TMR_CCR_CS_2(x) (((x) & 0x3) << 5)
#endif /* __ASM_MACH_REGS_TIMERS_H */
/*
* linux/arch/arm/mach-mmp/include/mach/system.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_MACH_SYSTEM_H
#define __ASM_MACH_SYSTEM_H
static inline void arch_idle(void)
{
cpu_do_idle();
}
static inline void arch_reset(char mode)
{
cpu_reset(0);
}
#endif /* __ASM_MACH_SYSTEM_H */
/*
* linux/arch/arm/mach-mmp/include/mach/timex.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define CLOCK_TICK_RATE 3250000
/*
* arch/arm/mach-mmp/include/mach/uncompress.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/serial_reg.h>
#include <mach/addr-map.h>
#define UART1_BASE (APB_PHYS_BASE + 0x36000)
#define UART2_BASE (APB_PHYS_BASE + 0x17000)
#define UART3_BASE (APB_PHYS_BASE + 0x18000)
static inline void putc(char c)
{
volatile unsigned long *UART = (unsigned long *)UART2_BASE;
/* UART enabled? */
if (!(UART[UART_IER] & UART_IER_UUE))
return;
while (!(UART[UART_LSR] & UART_LSR_THRE))
barrier();
UART[UART_TX] = c;
}
/*
* This does not append a newline
*/
static inline void flush(void)
{
}
/*
* nothing to do
*/
#define arch_decomp_setup()
#define arch_decomp_wdog()
/*
* linux/arch/arm/mach-mmp/include/mach/vmalloc.h
*/
#define VMALLOC_END 0xfe000000
/*
* linux/arch/arm/mach-mmp/irq.c
*
* Generic IRQ handling, GPIO IRQ demultiplexing, etc.
*
* Author: Bin Yang <bin.yang@marvell.com>
* Created: Sep 30, 2008
* Copyright: Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <mach/regs-icu.h>
#include "common.h"
#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ)
#define PRIORITY_DEFAULT 0x1
#define PRIORITY_NONE 0x0 /* means IRQ disabled */
static void icu_mask_irq(unsigned int irq)
{
__raw_writel(PRIORITY_NONE, ICU_INT_CONF(irq));
}
static void icu_unmask_irq(unsigned int irq)
{
__raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(irq));
}
static struct irq_chip icu_irq_chip = {
.name = "icu_irq",
.ack = icu_mask_irq,
.mask = icu_mask_irq,
.unmask = icu_unmask_irq,
};
void __init icu_init_irq(void)
{
int irq;
for (irq = 0; irq < 64; irq++) {
icu_mask_irq(irq);
set_irq_chip(irq, &icu_irq_chip);
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
}
}
/*
* linux/arch/arm/mach-mmp/pxa168.c
*
* Code specific to PXA168
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <asm/mach/time.h>
#include <mach/addr-map.h>
#include <mach/cputype.h>
#include <mach/regs-apbc.h>
#include <mach/irqs.h>
#include <mach/dma.h>
#include <mach/devices.h>
#include "common.h"
#include "clock.h"
void __init pxa168_init_irq(void)
{
icu_init_irq();
}
/* APB peripheral clocks */
static APBC_CLK(uart1, PXA168_UART1, 1, 14745600);
static APBC_CLK(uart2, PXA168_UART2, 1, 14745600);
/* device and clock bindings */
static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
};
static int __init pxa168_init(void)
{
if (cpu_is_pxa168()) {
pxa_init_dma(IRQ_PXA168_DMA_INT0, 32);
clks_register(ARRAY_AND_SIZE(pxa168_clkregs));
}
return 0;
}
postcore_initcall(pxa168_init);
/* system timer - clock enabled, 3.25MHz */
#define TIMER_CLK_RST (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3))
static void __init pxa168_timer_init(void)
{
/* this is early, we have to initialize the CCU registers by
* ourselves instead of using clk_* API. Clock rate is defined
* by APBC_TIMERS_CLK_RST (3.25MHz) and enabled free-running
*/
__raw_writel(APBC_APBCLK | APBC_RST, APBC_PXA168_TIMERS);
/* 3.25MHz, bus/functional clock enabled, release reset */
__raw_writel(TIMER_CLK_RST, APBC_PXA168_TIMERS);
timer_init(IRQ_PXA168_TIMER1);
}
struct sys_timer pxa168_timer = {
.init = pxa168_timer_init,
};
/* on-chip devices */
PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22);
PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24);
/*
* linux/arch/arm/mach-mmp/time.c
*
* Support for clocksource and clockevents
*
* Copyright (C) 2008 Marvell International Ltd.
* All rights reserved.
*
* 2008-04-11: Jason Chagas <Jason.chagas@marvell.com>
* 2008-10-08: Bin Yang <bin.yang@marvell.com>
*
* The timers module actually includes three timers, each timer with upto
* three match comparators. Timer #0 is used here in free-running mode as
* the clock source, and match comparator #1 used as clock event device.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/cnt32_to_63.h>
#include <mach/addr-map.h>
#include <mach/regs-timers.h>
#include <mach/irqs.h>
#include "clock.h"
#define TIMERS_VIRT_BASE TIMERS1_VIRT_BASE
#define MAX_DELTA (0xfffffffe)
#define MIN_DELTA (16)
#define TCR2NS_SCALE_FACTOR 10
static unsigned long tcr2ns_scale;
static void __init set_tcr2ns_scale(unsigned long tcr_rate)
{
unsigned long long v = 1000000000ULL << TCR2NS_SCALE_FACTOR;
do_div(v, tcr_rate);
tcr2ns_scale = v;
/*
* We want an even value to automatically clear the top bit
* returned by cnt32_to_63() without an additional run time
* instruction. So if the LSB is 1 then round it up.
*/
if (tcr2ns_scale & 1)
tcr2ns_scale++;
}
/*
* FIXME: the timer needs some delay to stablize the counter capture
*/
static inline uint32_t timer_read(void)
{
int delay = 100;
__raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(0));
while (delay--)
cpu_relax();
return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(0));
}
unsigned long long sched_clock(void)
{
unsigned long long v = cnt32_to_63(timer_read());
return (v * tcr2ns_scale) >> TCR2NS_SCALE_FACTOR;
}
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;
/* disable and clear pending interrupt status */
__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
__raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0));
c->event_handler(c);
return IRQ_HANDLED;
}
static int timer_set_next_event(unsigned long delta,
struct clock_event_device *dev)
{
unsigned long flags, next;
local_irq_save(flags);
/* clear pending interrupt status and enable */
__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
__raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
next = timer_read() + delta;
__raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
local_irq_restore(flags);
return 0;
}
static void timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *dev)
{
unsigned long flags;
local_irq_save(flags);
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* disable the matching interrupt */
__raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0));
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
local_irq_restore(flags);
}
static struct clock_event_device ckevt = {
.name = "clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.rating = 200,
.set_next_event = timer_set_next_event,
.set_mode = timer_set_mode,
};
static cycle_t clksrc_read(void)
{
return timer_read();
}
static struct clocksource cksrc = {
.name = "clocksource",
.shift = 20,
.rating = 200,
.read = clksrc_read,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static void __init timer_config(void)
{
uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
uint32_t cer = __raw_readl(TIMERS_VIRT_BASE + TMR_CER);
uint32_t cmr = __raw_readl(TIMERS_VIRT_BASE + TMR_CMR);
__raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */
ccr &= TMR_CCR_CS_0(0x3);
__raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
/* free-running mode */
__raw_writel(cmr | 0x01, TIMERS_VIRT_BASE + TMR_CMR);
__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */
__raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */
__raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
/* enable timer counter */
__raw_writel(cer | 0x01, TIMERS_VIRT_BASE + TMR_CER);
}
static struct irqaction timer_irq = {
.name = "timer",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = timer_interrupt,
.dev_id = &ckevt,
};
void __init timer_init(int irq)
{
timer_config();
set_tcr2ns_scale(CLOCK_TICK_RATE);
ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift);
ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt);
ckevt.min_delta_ns = clockevent_delta2ns(MIN_DELTA, &ckevt);
ckevt.cpumask = cpumask_of(0);
cksrc.mult = clocksource_hz2mult(CLOCK_TICK_RATE, cksrc.shift);
setup_irq(irq, &timer_irq);
clocksource_register(&cksrc);
clockevents_register_device(&ckevt);
}
......@@ -340,6 +340,17 @@ config CPU_XSC3
select CPU_TLB_V4WBI if MMU
select IO_36
# Marvell PJ1 (Mohawk)
config CPU_MOHAWK
bool
select CPU_32v5
select CPU_ABRT_EV5T
select CPU_PABRT_NOIFAR
select CPU_CACHE_VIVT
select CPU_CP15_MMU
select CPU_TLB_V4WBI if MMU
select CPU_COPY_V4WB if MMU
# Feroceon
config CPU_FEROCEON
bool
......@@ -569,7 +580,7 @@ comment "Processor Features"
config ARM_THUMB
bool "Support Thumb user binaries"
depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON
depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V7 || CPU_FEROCEON
default y
help
Say Y if you want to include kernel support for running user space
......@@ -653,7 +664,7 @@ config CPU_CACHE_ROUND_ROBIN
config CPU_BPREDICT_DISABLE
bool "Disable branch prediction"
depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7
depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7
help
Say Y here to disable branch prediction. If unsure, say N.
......
......@@ -70,6 +70,7 @@ obj-$(CONFIG_CPU_SA110) += proc-sa110.o
obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o
obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o
obj-$(CONFIG_CPU_V6) += proc-v6.o
obj-$(CONFIG_CPU_V7) += proc-v7.o
......
/*
* linux/arch/arm/mm/proc-mohawk.S: MMU functions for Marvell PJ1 core
*
* PJ1 (codename Mohawk) is a hybrid of the xscale3 and Marvell's own core.
*
* Heavily based on proc-arm926.S and proc-xsc3.S
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
#include <asm/hwcap.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/ptrace.h>
#include "proc-macros.S"
/*
* This is the maximum size of an area which will be flushed. If the
* area is larger than this, then we flush the whole cache.
*/
#define CACHE_DLIMIT 32768
/*
* The cache line size of the L1 D cache.
*/
#define CACHE_DLINESIZE 32
/*
* cpu_mohawk_proc_init()
*/
ENTRY(cpu_mohawk_proc_init)
mov pc, lr
/*
* cpu_mohawk_proc_fin()
*/
ENTRY(cpu_mohawk_proc_fin)
stmfd sp!, {lr}
mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
msr cpsr_c, ip
bl mohawk_flush_kern_cache_all
mrc p15, 0, r0, c1, c0, 0 @ ctrl register
bic r0, r0, #0x1800 @ ...iz...........
bic r0, r0, #0x0006 @ .............ca.
mcr p15, 0, r0, c1, c0, 0 @ disable caches
ldmfd sp!, {pc}
/*
* cpu_mohawk_reset(loc)
*
* Perform a soft reset of the system. Put the CPU into the
* same state as it would be if it had been reset, and branch
* to what would be the reset vector.
*
* loc: location to jump to for soft reset
*
* (same as arm926)
*/
.align 5
ENTRY(cpu_mohawk_reset)
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x0007 @ .............cam
bic ip, ip, #0x1100 @ ...i...s........
mcr p15, 0, ip, c1, c0, 0 @ ctrl register
mov pc, r0
/*
* cpu_mohawk_do_idle()
*
* Called with IRQs disabled
*/
.align 5
ENTRY(cpu_mohawk_do_idle)
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
mov pc, lr
/*
* flush_user_cache_all()
*
* Clean and invalidate all cache entries in a particular
* address space.
*/
ENTRY(mohawk_flush_user_cache_all)
/* FALLTHROUGH */
/*
* flush_kern_cache_all()
*
* Clean and invalidate the entire cache.
*/
ENTRY(mohawk_flush_kern_cache_all)
mov r2, #VM_EXEC
mov ip, #0
__flush_whole_cache:
mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache
tst r2, #VM_EXEC
mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcrne p15, 0, ip, c7, c10, 0 @ drain write buffer
mov pc, lr
/*
* flush_user_cache_range(start, end, flags)
*
* Clean and invalidate a range of cache entries in the
* specified address range.
*
* - start - start address (inclusive)
* - end - end address (exclusive)
* - flags - vm_flags describing address space
*
* (same as arm926)
*/
ENTRY(mohawk_flush_user_cache_range)
mov ip, #0
sub r3, r1, r0 @ calculate total size
cmp r3, #CACHE_DLIMIT
bgt __flush_whole_cache
1: tst r2, #VM_EXEC
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
add r0, r0, #CACHE_DLINESIZE
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
tst r2, #VM_EXEC
mcrne p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
/*
* coherent_kern_range(start, end)
*
* Ensure coherency between the Icache and the Dcache in the
* region described by start, end. If you have non-snooping
* Harvard caches, you need to implement this function.
*
* - start - virtual start address
* - end - virtual end address
*/
ENTRY(mohawk_coherent_kern_range)
/* FALLTHROUGH */
/*
* coherent_user_range(start, end)
*
* Ensure coherency between the Icache and the Dcache in the
* region described by start, end. If you have non-snooping
* Harvard caches, you need to implement this function.
*
* - start - virtual start address
* - end - virtual end address
*
* (same as arm926)
*/
ENTRY(mohawk_coherent_user_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
/*
* flush_kern_dcache_page(void *page)
*
* Ensure no D cache aliasing occurs, either with itself or
* the I cache
*
* - addr - page aligned address
*/
ENTRY(mohawk_flush_kern_dcache_page)
add r1, r0, #PAGE_SZ
1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
/*
* dma_inv_range(start, end)
*
* Invalidate (discard) the specified virtual address range.
* May not write back any entries. If 'start' or 'end'
* are not cache line aligned, those lines must be written
* back.
*
* - start - virtual start address
* - end - virtual end address
*
* (same as v4wb)
*/
ENTRY(mohawk_dma_inv_range)
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
tst r1, #CACHE_DLINESIZE - 1
mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
/*
* dma_clean_range(start, end)
*
* Clean the specified virtual address range.
*
* - start - virtual start address
* - end - virtual end address
*
* (same as v4wb)
*/
ENTRY(mohawk_dma_clean_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
/*
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
*
* - start - virtual start address
* - end - virtual end address
*/
ENTRY(mohawk_dma_flush_range)
bic r0, r0, #CACHE_DLINESIZE - 1
1:
mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
ENTRY(mohawk_cache_fns)
.long mohawk_flush_kern_cache_all
.long mohawk_flush_user_cache_all
.long mohawk_flush_user_cache_range
.long mohawk_coherent_kern_range
.long mohawk_coherent_user_range
.long mohawk_flush_kern_dcache_page
.long mohawk_dma_inv_range
.long mohawk_dma_clean_range
.long mohawk_dma_flush_range
ENTRY(cpu_mohawk_dcache_clean_area)
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
subs r1, r1, #CACHE_DLINESIZE
bhi 1b
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
/*
* cpu_mohawk_switch_mm(pgd)
*
* Set the translation base pointer to be as described by pgd.
*
* pgd: new page tables
*/
.align 5
ENTRY(cpu_mohawk_switch_mm)
mov ip, #0
mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcr p15, 0, ip, c7, c10, 4 @ drain WB
orr r0, r0, #0x18 @ cache the page table in L2
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
mov pc, lr
/*
* cpu_mohawk_set_pte_ext(ptep, pte, ext)
*
* Set a PTE and flush it out
*/
.align 5
ENTRY(cpu_mohawk_set_pte_ext)
armv3_set_pte_ext
mov r0, r0
mcr p15, 0, r0, c7, c10, 1 @ clean D entry
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
__INIT
.type __mohawk_setup, #function
__mohawk_setup:
mov r0, #0
mcr p15, 0, r0, c7, c7 @ invalidate I,D caches
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs
orr r4, r4, #0x18 @ cache the page table in L2
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
mov r0, #0 @ don't allow CP access
mcr p15, 0, r0, c15, c1, 0 @ write CP access register
adr r5, mohawk_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0 @ get control register
bic r0, r0, r5
orr r0, r0, r6
mov pc, lr
.size __mohawk_setup, . - __mohawk_setup
/*
* R
* .RVI ZFRS BLDP WCAM
* .011 1001 ..00 0101
*
*/
.type mohawk_crval, #object
mohawk_crval:
crval clear=0x00007f3f, mmuset=0x00003905, ucset=0x00001134
__INITDATA
/*
* Purpose : Function pointers used to access above functions - all calls
* come through these
*/
.type mohawk_processor_functions, #object
mohawk_processor_functions:
.word v5t_early_abort
.word pabort_noifar
.word cpu_mohawk_proc_init
.word cpu_mohawk_proc_fin
.word cpu_mohawk_reset
.word cpu_mohawk_do_idle
.word cpu_mohawk_dcache_clean_area
.word cpu_mohawk_switch_mm
.word cpu_mohawk_set_pte_ext
.size mohawk_processor_functions, . - mohawk_processor_functions
.section ".rodata"
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv5te"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
cpu_elf_name:
.asciz "v5"
.size cpu_elf_name, . - cpu_elf_name
.type cpu_mohawk_name, #object
cpu_mohawk_name:
.asciz "Marvell 88SV331x"
.size cpu_mohawk_name, . - cpu_mohawk_name
.align
.section ".proc.info.init", #alloc, #execinstr
.type __88sv331x_proc_info,#object
__88sv331x_proc_info:
.long 0x56158000 @ Marvell 88SV331x (MOHAWK)
.long 0xfffff000
.long PMD_TYPE_SECT | \
PMD_SECT_BUFFERABLE | \
PMD_SECT_CACHEABLE | \
PMD_BIT4 | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
.long PMD_TYPE_SECT | \
PMD_BIT4 | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
b __mohawk_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_mohawk_name
.long mohawk_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
.long mohawk_cache_fns
.size __88sv331x_proc_info, . - __88sv331x_proc_info
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册