Commit 01c0a4a6 authored by Deepak Saxena's avatar Deepak Saxena

Merge bk://bk.arm.linux.org.uk/linux-2.6-rmk

into plexity.net:/home/dsaxena/src/linux-2.6-for-rmk
parents adf791bd cda97ee3
README on the SDRAM Controller for the LH7a40X
==============================================
The standard configuration for the SDRAM controller generates a sparse
memory array. The precise layout is determined by the SDRAM chips. A
default kernel configuration assembles the discontiguous memory
regions into separate memory nodes via the NUMA (Non-Uniform Memory
Architecture) facilities. In this default configuration, the kernel
is forgiving about the precise layout. As long as it is given an
accurate picture of available memory by the bootloader the kernel will
execute correctly.
The SDRC supports a mode where some of the chip select lines are
swapped in order to make SDRAM look like a synchronous ROM. Setting
this bit means that the RAM will present as a contiguous array. Some
programmers prefer this to the discontiguous layout. Be aware that
may be a penalty for this feature where some some configurations of
memory are significantly reduced; i.e. 64MiB of RAM appears as only 32
MiB.
There are a couple of configuration options to override the default
behavior. When the SROMLL bit is set and memory appears as a
contiguous array, there is no reason to support NUMA.
CONFIG_LH7A40X_CONTIGMEM disables NUMA support. When physical memory
is discontiguous, the memory tables are organized such that there are
two banks per nodes with a small gap between them. This layout wastes
some kernel memory for page tables representing non-existent memory.
CONFIG_LH7A40X_ONE_BANK_PER_NODE optimizes the node tables such that
there are no gaps. These options control the low level organization
of the memory management tables in ways that may prevent the kernel
from booting or may cause the kernel to allocated excessively large
page tables. Be warned. Only change these options if you know what
you are doing. The default behavior is a reasonable compromise that
will suit all users.
--
A typical 32MiB system with the default configuration options will
find physical memory managed as follows.
node 0: 0xc0000000 4MiB
0xc1000000 4MiB
node 1: 0xc4000000 4MiB
0xc5000000 4MiB
node 2: 0xc8000000 4MiB
0xc9000000 4MiB
node 3: 0xcc000000 4MiB
0xcd000000 4MiB
Setting CONFIG_LH7A40X_ONE_BANK_PER_NODE will put each bank into a
separate node.
......@@ -246,10 +246,10 @@ menu "General setup"
# Select various configuration options depending on the machine type
config DISCONTIGMEM
bool
depends on ARCH_EDB7211 || ARCH_SA1100 || ARCH_LH7A40X
depends on ARCH_EDB7211 || ARCH_SA1100 || (ARCH_LH7A40X && !LH7A40X_SROMLL)
default y
help
Say Y to upport efficient handling of discontiguous physical memory,
Say Y to support efficient handling of discontiguous physical memory,
for architectures which are either NUMA (Non-Uniform Memory Access)
or have huge holes in the physical address space for other reasons.
See <file:Documentation/vm/numa> for more.
......
......@@ -591,7 +591,8 @@
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
ldr \rx, =0x80000700 @ physical base address
mov \rx, #0x00000700 @ offset from base
orreq \rx, \rx, #0x80000000 @ physical base
orrne \rx, \rx, #0xf8000000 @ virtual base
.endm
......
......@@ -4,7 +4,7 @@
# Object file lists.
obj-y := core.o lm.o time.o
obj-y := clock.o core.o lm.o time.o
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
......
/*
* linux/arch/arm/mach-integrator/clock.c
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* 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/errno.h>
#include <linux/err.h>
#include <asm/semaphore.h>
#include <asm/hardware/clock.h>
#include <asm/hardware/icst525.h>
#include "clock.h"
static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
down(&clocks_sem);
list_for_each_entry(p, &clocks, node) {
if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
break;
}
}
up(&clocks_sem);
return clk;
}
EXPORT_SYMBOL(clk_get);
void clk_put(struct clk *clk)
{
module_put(clk->owner);
}
EXPORT_SYMBOL(clk_put);
int clk_enable(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_disable);
int clk_use(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_use);
void clk_unuse(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_unuse);
unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
return rate;
}
EXPORT_SYMBOL(clk_round_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret = -EIO;
if (clk->setvco) {
struct icst525_vco vco;
vco = icst525_khz_to_vco(clk->params, rate);
clk->rate = icst525_khz(clk->params, vco);
printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
clk->name, vco.s, vco.r, vco.v);
clk->setvco(clk, vco);
ret = 0;
}
return 0;
}
EXPORT_SYMBOL(clk_set_rate);
/*
* These are fixed clocks.
*/
static struct clk kmi_clk = {
.name = "KMIREFCLK",
.rate = 24000000,
};
static struct clk uart_clk = {
.name = "UARTCLK",
.rate = 14745600,
};
int clk_register(struct clk *clk)
{
down(&clocks_sem);
list_add(&clk->node, &clocks);
up(&clocks_sem);
return 0;
}
EXPORT_SYMBOL(clk_register);
void clk_unregister(struct clk *clk)
{
down(&clocks_sem);
list_del(&clk->node);
up(&clocks_sem);
}
EXPORT_SYMBOL(clk_unregister);
static int __init clk_init(void)
{
clk_register(&kmi_clk);
clk_register(&uart_clk);
return 0;
}
arch_initcall(clk_init);
/*
* linux/arch/arm/mach-integrator/clock.h
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* 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.
*/
struct module;
struct icst525_params;
struct clk {
struct list_head node;
unsigned long rate;
struct module *owner;
const char *name;
const struct icst525_params *params;
void *data;
void (*setvco)(struct clk *, struct icst525_vco vco);
};
int clk_register(struct clk *clk);
void clk_unregister(struct clk *clk);
......@@ -25,13 +25,16 @@
#include <asm/arch/impd1.h>
#include <asm/sizes.h>
#include "clock.h"
static int module_id;
module_param_named(lmid, module_id, int, 0444);
MODULE_PARM_DESC(lmid, "logic module stack position");
struct impd1_module {
void *base;
void *base;
struct clk vcos[2];
};
static const struct icst525_params impd1_vco_params = {
......@@ -43,25 +46,20 @@ static const struct icst525_params impd1_vco_params = {
.rd_max = 120,
};
void impd1_set_vco(struct device *dev, int vconr, unsigned long period)
static void impd1_setvco(struct clk *clk, struct icst525_vco vco)
{
struct impd1_module *impd1 = dev_get_drvdata(dev);
struct icst525_vco vco;
struct impd1_module *impd1 = clk->data;
int vconr = clk - impd1->vcos;
u32 val;
vco = icst525_ps_to_vco(&impd1_vco_params, period);
pr_debug("Guessed VCO reg params: S=%d R=%d V=%d\n",
vco.s, vco.r, vco.v);
val = vco.v | (vco.r << 9) | (vco.s << 16);
writel(0xa05f, impd1->base + IMPD1_LOCK);
switch (vconr) {
case 1:
case 0:
writel(val, impd1->base + IMPD1_OSC1);
break;
case 2:
case 1:
writel(val, impd1->base + IMPD1_OSC2);
break;
}
......@@ -77,8 +75,6 @@ void impd1_set_vco(struct device *dev, int vconr, unsigned long period)
#endif
}
EXPORT_SYMBOL(impd1_set_vco);
void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
{
struct impd1_module *impd1 = dev_get_drvdata(dev);
......@@ -140,6 +136,11 @@ static struct impd1_device impd1_devs[] = {
}
};
static const char *impd1_vconames[2] = {
"CLCDCLK",
"AUXVCO2",
};
static int impd1_probe(struct lm_device *dev)
{
struct impd1_module *impd1;
......@@ -168,6 +169,16 @@ static int impd1_probe(struct lm_device *dev)
printk("IM-PD1 found at 0x%08lx\n", dev->resource.start);
for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) {
impd1->vcos[i].owner = THIS_MODULE,
impd1->vcos[i].name = impd1_vconames[i],
impd1->vcos[i].params = &impd1_vco_params,
impd1->vcos[i].data = impd1,
impd1->vcos[i].setvco = impd1_setvco;
clk_register(&impd1->vcos[i]);
}
for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
struct impd1_device *idev = impd1_devs + i;
struct amba_device *d;
......@@ -216,6 +227,7 @@ static void impd1_remove(struct lm_device *dev)
{
struct impd1_module *impd1 = lm_get_drvdata(dev);
struct list_head *l, *n;
int i;
list_for_each_safe(l, n, &dev->dev.children) {
struct device *d = list_to_dev(l);
......@@ -223,6 +235,9 @@ static void impd1_remove(struct lm_device *dev)
device_unregister(d);
}
for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++)
clk_unregister(&impd1->vcos[i]);
lm_set_drvdata(dev, NULL);
iounmap(impd1->base);
......
......@@ -23,6 +23,7 @@
#include <asm/mach-types.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/amba_kmi.h>
#include <asm/hardware/icst525.h>
#include <asm/arch/lm.h>
......@@ -32,12 +33,16 @@
#include <asm/mach/mmc.h>
#include <asm/mach/map.h>
#include "clock.h"
#define INTCP_PA_MMC_BASE 0x1c000000
#define INTCP_PA_AACI_BASE 0x1d000000
#define INTCP_PA_FLASH_BASE 0x24000000
#define INTCP_FLASH_SIZE SZ_32M
#define INTCP_PA_CLCD_BASE 0xc0000000
#define INTCP_VA_CIC_BASE 0xf1000040
#define INTCP_VA_PIC_BASE 0xf1400000
#define INTCP_VA_SIC_BASE 0xfca00000
......@@ -209,6 +214,44 @@ static void __init intcp_init_irq(void)
pic_unmask_irq(IRQ_CP_CPPLDINT);
}
/*
* Clock handling
*/
#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
#define CM_AUXOSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+0x1c)
static const struct icst525_params cp_auxvco_params = {
.ref = 24000,
.vco_max = 320000,
.vd_min = 8,
.vd_max = 263,
.rd_min = 3,
.rd_max = 65,
};
static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco)
{
u32 val;
val = readl(CM_AUXOSC) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
writel(0xa05f, CM_LOCK);
writel(val, CM_AUXOSC);
writel(0, CM_LOCK);
}
static struct clk cp_clcd_clk = {
.name = "CLCDCLK",
.params = &cp_auxvco_params,
.setvco = cp_auxvco_set,
};
static struct clk cp_mmci_clk = {
.name = "MCLK",
.rate = 33000000,
};
/*
* Flash handling.
*/
......@@ -340,15 +383,34 @@ static struct amba_device aaci_device = {
.periphid = 0,
};
static struct amba_device clcd_device = {
.dev = {
.bus_id = "mb:c0",
.coherent_dma_mask = ~0,
},
.res = {
.start = INTCP_PA_CLCD_BASE,
.end = INTCP_PA_CLCD_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.dma_mask = ~0,
.irq = { IRQ_CP_CLCDCINT, NO_IRQ },
.periphid = 0,
};
static struct amba_device *amba_devs[] __initdata = {
&mmc_device,
&aaci_device,
&clcd_device,
};
static void __init intcp_init(void)
{
int i;
clk_register(&cp_clcd_clk);
clk_register(&cp_mmci_clk);
platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
......
......@@ -34,6 +34,37 @@ config ARCH_LH7A400
config ARCH_LH7A404
bool
config LH7A40X_CONTIGMEM
bool "Disable NUMA Support"
depends on ARCH_LH7A40X
help
Say Y here if your bootloader sets the SROMLL bit(s) in
the SDRAM controller, organizing memory as a contiguous
array. This option will disable CONFIG_DISCONTIGMEM and
force the kernel to manage all memory in one node.
Setting this option incorrectly may prevent the kernel from
booting. It is OK to leave it N.
For more information, consult
<file:Documentation/arm/Sharp-LH/SDRAM>.
config LH7A40X_ONE_BANK_PER_NODE
bool "Optimize NUMA Node Tables for Size"
depends on ARCH_LH7A40X && !LH7A40X_CONTIGMEM
help
Say Y here to produce compact memory node tables. By
default pairs of adjacent physical RAM banks are managed
together in a single node, incurring some wasted overhead
in the node tables, however also maintaining compatibility
with systems where physical memory is truly contiguous.
Setting this option incorrectly may prevent the kernel from
booting. It is OK to leave it N.
For more information, consult
<file:Documentation/arm/Sharp-LH/SDRAM>.
endmenu
endif
......@@ -2,4 +2,4 @@
# Makefile for the linux kernel.
#
obj-y := core.o
obj-y := core.o clock.o
/*
* linux/arch/arm/mach-versatile/clock.c
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* 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/errno.h>
#include <linux/err.h>
#include <asm/semaphore.h>
#include <asm/hardware/clock.h>
#include <asm/hardware/icst525.h>
#include "clock.h"
static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
down(&clocks_sem);
list_for_each_entry(p, &clocks, node) {
if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
break;
}
}
up(&clocks_sem);
return clk;
}
EXPORT_SYMBOL(clk_get);
void clk_put(struct clk *clk)
{
module_put(clk->owner);
}
EXPORT_SYMBOL(clk_put);
int clk_enable(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_disable);
int clk_use(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_use);
void clk_unuse(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_unuse);
unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
return rate;
}
EXPORT_SYMBOL(clk_round_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret = -EIO;
#if 0 // Not yet
if (clk->setvco) {
struct icst525_vco vco;
vco = icst525_khz_to_vco(clk->params, rate);
clk->rate = icst525_khz(clk->params, vco);
printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
clk->name, vco.s, vco.r, vco.v);
clk->setvco(clk, vco);
ret = 0;
}
#endif
return 0;
}
EXPORT_SYMBOL(clk_set_rate);
/*
* These are fixed clocks.
*/
static struct clk kmi_clk = {
.name = "KMIREFCLK",
.rate = 24000000,
};
static struct clk uart_clk = {
.name = "UARTCLK",
.rate = 24000000,
};
static struct clk mmci_clk = {
.name = "MCLK",
.rate = 33000000,
};
int clk_register(struct clk *clk)
{
down(&clocks_sem);
list_add(&clk->node, &clocks);
up(&clocks_sem);
return 0;
}
EXPORT_SYMBOL(clk_register);
void clk_unregister(struct clk *clk)
{
down(&clocks_sem);
list_del(&clk->node);
up(&clocks_sem);
}
EXPORT_SYMBOL(clk_unregister);
static int __init clk_init(void)
{
clk_register(&kmi_clk);
clk_register(&uart_clk);
clk_register(&mmci_clk);
return 0;
}
arch_initcall(clk_init);
/*
* linux/arch/arm/mach-versatile/clock.h
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* 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.
*/
struct module;
struct icst525_params;
struct clk {
struct list_head node;
unsigned long rate;
struct module *owner;
const char *name;
const struct icst525_params *params;
void *data;
void (*setvco)(struct clk *, struct icst525_vco vco);
};
int clk_register(struct clk *clk);
void clk_unregister(struct clk *clk);
......@@ -18,17 +18,19 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/amba_kmi.h>
#include <asm/hardware/clock.h>
#define KMI_BASE (kmi->base)
struct amba_kmi_port {
struct serio io;
struct amba_kmi_port *next;
struct clk *clk;
unsigned char *base;
unsigned int irq;
unsigned int divisor;
......@@ -67,21 +69,38 @@ static int amba_kmi_write(struct serio *io, unsigned char val)
static int amba_kmi_open(struct serio *io)
{
struct amba_kmi_port *kmi = io->driver;
unsigned int divisor;
int ret;
writeb(kmi->divisor, KMICLKDIV);
ret = clk_use(kmi->clk);
if (ret)
goto out;
ret = clk_enable(kmi->clk);
if (ret)
goto clk_unuse;
divisor = clk_get_rate(kmi->clk) / 8000000 - 1;
writeb(divisor, KMICLKDIV);
writeb(KMICR_EN, KMICR);
ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi);
if (ret) {
printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq);
writeb(0, KMICR);
return ret;
goto clk_disable;
}
writeb(KMICR_EN | KMICR_RXINTREN, KMICR);
return 0;
clk_disable:
clk_disable(kmi->clk);
clk_unuse:
clk_unuse(kmi->clk);
out:
return ret;
}
static void amba_kmi_close(struct serio *io)
......@@ -91,6 +110,8 @@ static void amba_kmi_close(struct serio *io)
writeb(0, KMICR);
free_irq(kmi->irq, kmi);
clk_disable(kmi->clk);
clk_unuse(kmi->clk);
}
static int amba_kmi_probe(struct amba_device *dev, void *id)
......@@ -124,14 +145,20 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
goto out;
}
kmi->irq = dev->irq[0];
kmi->divisor = 24 / 8 - 1;
kmi->clk = clk_get(&dev->dev, "KMIREFCLK");
if (IS_ERR(kmi->clk)) {
ret = PTR_ERR(kmi->clk);
goto unmap;
}
kmi->irq = dev->irq[0];
amba_set_drvdata(dev, kmi);
serio_register_port(&kmi->io);
return 0;
unmap:
iounmap(kmi->base);
out:
kfree(kmi);
amba_release_regions(dev);
......@@ -145,6 +172,7 @@ static int amba_kmi_remove(struct amba_device *dev)
amba_set_drvdata(dev, NULL);
serio_unregister_port(&kmi->io);
clk_put(kmi->clk);
iounmap(kmi->base);
kfree(kmi);
amba_release_regions(dev);
......
......@@ -44,6 +44,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/clock.h>
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
......@@ -68,6 +69,7 @@
*/
struct uart_amba_port {
struct uart_port port;
struct clk *clk;
unsigned int im; /* interrupt mask */
unsigned int old_status;
};
......@@ -351,12 +353,21 @@ static int pl011_startup(struct uart_port *port)
unsigned int cr;
int retval;
/*
* Try to enable the clock producer.
*/
retval = clk_enable(uap->clk);
if (retval)
goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
/*
* Allocate the IRQ
*/
retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
if (retval)
goto out;
goto clk_dis;
writew(UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
uap->port.membase + UART011_IFLS);
......@@ -391,6 +402,8 @@ static int pl011_startup(struct uart_port *port)
return 0;
clk_dis:
clk_disable(uap->clk);
out:
return retval;
}
......@@ -425,6 +438,11 @@ static void pl011_shutdown(struct uart_port *port)
val = readw(uap->port.membase + UART011_LCRH);
val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
writew(val, uap->port.membase + UART011_LCRH);
/*
* Shut down the clock producer
*/
clk_disable(uap->clk);
}
static void
......@@ -594,38 +612,40 @@ static struct uart_amba_port *amba_ports[UART_NR];
#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
static inline void
pl011_console_write_char(struct uart_port *port, char ch)
pl011_console_write_char(struct uart_amba_port *uap, char ch)
{
unsigned int status;
do {
status = readw(port->membase + UART01x_FR);
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_TXFF);
writew(ch, port->membase + UART01x_DR);
writew(ch, uap->port.membase + UART01x_DR);
}
static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_port *port = &amba_ports[co->index]->port;
struct uart_amba_port *uap = amba_ports[co->index];
unsigned int status, old_cr, new_cr;
int i;
clk_enable(uap->clk);
/*
* First save the CR then disable the interrupts
*/
old_cr = readw(port->membase + UART011_CR);
old_cr = readw(uap->port.membase + UART011_CR);
new_cr = old_cr & ~UART011_CR_CTSEN;
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
writew(new_cr, port->membase + UART011_CR);
writew(new_cr, uap->port.membase + UART011_CR);
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
pl011_console_write_char(port, s[i]);
pl011_console_write_char(uap, s[i]);
if (s[i] == '\n')
pl011_console_write_char(port, '\r');
pl011_console_write_char(uap, '\r');
}
/*
......@@ -633,19 +653,21 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* and restore the TCR
*/
do {
status = readw(port->membase + UART01x_FR);
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_BUSY);
writew(old_cr, port->membase + UART011_CR);
writew(old_cr, uap->port.membase + UART011_CR);
clk_disable(uap->clk);
}
static void __init
pl011_console_get_options(struct uart_port *port, int *baud,
pl011_console_get_options(struct uart_amba_port *uap, int *baud,
int *parity, int *bits)
{
if (readw(port->membase + UART011_CR) & UART01x_CR_UARTEN) {
if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, ibrd, fbrd;
lcr_h = readw(port->membase + UART011_LCRH);
lcr_h = readw(uap->port.membase + UART011_LCRH);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
......@@ -660,10 +682,10 @@ pl011_console_get_options(struct uart_port *port, int *baud,
else
*bits = 8;
ibrd = readw(port->membase + UART011_IBRD);
fbrd = readw(port->membase + UART011_FBRD);
ibrd = readw(uap->port.membase + UART011_IBRD);
fbrd = readw(uap->port.membase + UART011_FBRD);
*baud = port->uartclk * 4 / (64 * ibrd + fbrd);
*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
}
}
......@@ -685,10 +707,12 @@ static int __init pl011_console_setup(struct console *co, char *options)
co->index = 0;
uap = amba_ports[co->index];
uap->port.uartclk = clk_get_rate(uap->clk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
pl011_console_get_options(&uap->port, &baud, &parity, &bits);
pl011_console_get_options(uap, &baud, &parity, &bits);
return uart_set_options(&uap->port, co, baud, parity, bits, flow);
}
......@@ -747,16 +771,21 @@ static int pl011_probe(struct amba_device *dev, void *id)
}
memset(uap, 0, sizeof(struct uart_amba_port));
uap->clk = clk_get(&dev->dev, "UARTCLK");
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
goto unmap;
}
ret = clk_use(uap->clk);
if (ret)
goto putclk;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
uap->port.iotype = UPIO_MEM;
uap->port.irq = dev->irq[0];
#if 0 /* FIXME */
uap->port.uartclk = 14745600;
#else
uap->port.uartclk = 24000000;
#endif
uap->port.fifosize = 16;
uap->port.ops = &amba_pl011_pops;
uap->port.flags = UPF_BOOT_AUTOCONF;
......@@ -769,6 +798,10 @@ static int pl011_probe(struct amba_device *dev, void *id)
if (ret) {
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
clk_unuse(uap->clk);
putclk:
clk_put(uap->clk);
unmap:
iounmap(base);
free:
kfree(uap);
......@@ -791,6 +824,8 @@ static int pl011_remove(struct amba_device *dev)
amba_ports[i] = NULL;
iounmap(uap->port.membase);
clk_unuse(uap->clk);
clk_put(uap->clk);
kfree(uap);
return 0;
}
......
This diff is collapsed.
......@@ -14,6 +14,5 @@
struct device;
void impd1_set_vco(struct device *dev, int vconr, unsigned long period);
void impd1_tweak_control(struct device *dev, u32 mask, u32 val);
......@@ -6,14 +6,14 @@
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*
* Refer to <file:Documentation/arm/Sharp-LH/SDRAM> for more information.
*
*/
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
#define BANKS_PER_NODE 1 /* Define as either 1 or 2 */
/*
* Physical DRAM offset.
*/
......@@ -30,57 +30,30 @@
#define __bus_to_virt(x) __phys_to_virt(x)
#ifdef CONFIG_DISCONTIGMEM
/*
* Because of the wide memory address space between physical RAM
* banks, it's convenient to use Linux's NUMA support to represent our
* memory map. Assuming all memory nodes have equal access
* characteristics, we then have a generic discontiguous memory setup.
*
* Of course, all this isn't mandatory for implementations with only
* one used memory bank. For those, simply undefine
* CONFIG_DISCONTIGMEM. However, keep in mind that a featurefull
* system will need more than 4MiB of RAM.
*
* The contiguous memory blocks are small enough that it pays to
* aggregate two banks into one node. Setting BANKS_PER_NODE to 2
* puts pairs of banks into a node.
*
* A typical layout would start like this:
*
* node 0: 0xc0000000
* 0xc1000000
* node 1: 0xc4000000
* 0xc5000000
* node 2: 0xc8000000
* 0xc9000000
*
* The proximity of the pairs of blocks makes it feasible to combine them.
*
*/
/*
* Given a kernel address, find the home node of the underlying memory.
*/
#if BANKS_PER_NODE==1
#define KVADDR_TO_NID(addr) \
# ifdef CONFIG_LH7A40X_ONE_BANK_PER_NODE
# define KVADDR_TO_NID(addr) \
( ((((unsigned long) (addr) - PAGE_OFFSET) >> 24) & 1)\
| ((((unsigned long) (addr) - PAGE_OFFSET) >> 25) & ~1))
#else /* 2 banks per node */
#define KVADDR_TO_NID(addr) \
((unsigned long) (addr) - PAGE_OFFSET) >> 26)
#endif
# else /* 2 banks per node */
# define KVADDR_TO_NID(addr) \
(((unsigned long) (addr) - PAGE_OFFSET) >> 26)
# endif
/*
* Given a page frame number, convert it to a node id.
*/
#if BANKS_PER_NODE==1
#define PFN_TO_NID(pfn) \
# ifdef CONFIG_LH7A40X_ONE_BANK_PER_NODE
# define PFN_TO_NID(pfn) \
(((((pfn) - PHYS_PFN_OFFSET) >> (24 - PAGE_SHIFT)) & 1)\
| ((((pfn) - PHYS_PFN_OFFSET) >> (25 - PAGE_SHIFT)) & ~1))
#else /* 2 banks per node */
#define PFN_TO_NID(addr) \
# else /* 2 banks per node */
# define PFN_TO_NID(pfn) \
(((pfn) - PHYS_PFN_OFFSET) >> (26 - PAGE_SHIFT))
#endif
......@@ -88,13 +61,13 @@
* Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
* and return the mem_map of that node.
*/
#define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr))
# define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr))
/*
* Given a page frame number, find the owning node of the memory
* and return the mem_map of that node.
*/
#define PFN_TO_MAPBASE(pfn) NODE_MEM_MAP(PFN_TO_NID(pfn))
# define PFN_TO_MAPBASE(pfn) NODE_MEM_MAP(PFN_TO_NID(pfn))
/*
* Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory
......@@ -102,17 +75,17 @@
* node's mem_map.
*/
#if BANKS_PER_NODE==1
#define LOCAL_MAP_NR(addr) \
# ifdef CONFIG_LH7A40X_ONE_BANK_PER_NODE
# define LOCAL_MAP_NR(addr) \
(((unsigned long)(addr) & 0x003fffff) >> PAGE_SHIFT)
#else /* 2 banks per node */
#define LOCAL_MAP_NR(addr) \
# else /* 2 banks per node */
# define LOCAL_MAP_NR(addr) \
(((unsigned long)(addr) & 0x01ffffff) >> PAGE_SHIFT)
#endif
# endif
#else
#define PFN_TO_NID(addr) (0)
# define PFN_TO_NID(addr) (0)
#endif
......
/*
* linux/include/asm-arm/hardware/clock.h
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
* 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 ASMARM_CLOCK_H
#define ASMARM_CLOCK_H
struct device;
/*
* The base API.
*/
/*
* struct clk - an machine class defined object / cookie.
*/
struct clk;
/**
* clk_get - lookup and obtain a reference to a clock producer.
* @dev: device for clock "consumer"
* @id: device ID
*
* Returns a struct clk corresponding to the clock producer, or
* valid IS_ERR() condition containing errno.
*/
struct clk *clk_get(struct device *dev, const char *id);
/**
* clk_enable - inform the system when the clock source should be running.
* @clk: clock source
*
* If the clock can not be enabled/disabled, this should return success.
*
* Returns success (0) or negative errno.
*/
int clk_enable(struct clk *clk);
/**
* clk_disable - inform the system when the clock source is no longer required.
* @clk: clock source
*/
void clk_disable(struct clk *clk);
/**
* clk_use - increment the use count
* @clk: clock source
*
* Returns success (0) or negative errno.
*/
int clk_use(struct clk *clk);
/**
* clk_unuse - decrement the use count
* @clk: clock source
*/
void clk_unuse(struct clk *clk);
/**
* clk_get_rate - obtain the current clock rate for a clock source.
* This is only valid once the clock source has been enabled.
* @clk: clock source
*/
unsigned long clk_get_rate(struct clk *clk);
/**
* clk_put - "free" the clock source
* @clk: clock source
*/
void clk_put(struct clk *clk);
/*
* The remaining APIs are optional for machine class support.
*/
/**
* clk_round_rate - adjust a rate to the exact rate a clock can provide
* @clk: clock source
* @rate: desired clock rate in kHz
*
* Returns rounded clock rate, or negative errno.
*/
long clk_round_rate(struct clk *clk, unsigned long rate);
/**
* clk_set_rate - set the clock rate for a clock source
* @clk: clock source
* @rate: desired clock rate in kHz
*
* Returns success (0) or negative errno.
*/
int clk_set_rate(struct clk *clk, unsigned long rate);
/**
* clk_set_parent - set the parent clock source for this clock
* @clk: clock source
* @parent: parent clock source
*
* Returns success (0) or negative errno.
*/
int clk_set_parent(struct clk *clk, struct clk *parent);
/**
* clk_get_parent - get the parent clock source for this clock
* @clk: clock source
*
* Returns struct clk corresponding to parent clock source, or
* valid IS_ERR() condition containing errno.
*/
struct clk *clk_get_parent(struct clk *clk);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment