MIPS: Loongson: Naming style cleanup and rework

Currently, code of Loongson-2/3 is under loongson directory and code of
Loongson-1 is under loongson1 directory. Besides, there are Kconfig
options such as MACH_LOONGSON and MACH_LOONGSON1. This naming style is
very ugly and confusing. Since Loongson-2/3 are both 64-bit general-
purpose CPU while Loongson-1 is 32-bit SoC, we rename both file names
and Kconfig symbols from loongson/loongson1 to loongson64/loongson32.

[ralf@linux-mips.org: Resolve a number of simple conflicts.]

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Cc: Steven J. Hill <Steven.Hill@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: Fuxin Zhang <zhangfx@lemote.com>
Cc: Zhangjin Wu <wuzhangjin@gmail.com>
Cc: Kelvin Cheung <keguang.zhang@gmail.com>
Patchwork: https://patchwork.linux-mips.org/patch/9790/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Huacai Chen
2015-04-21 10:00:35 +08:00
committed by Ralf Baechle
vanhempi abcc82b19f
commit 30ad29bb48
102 muutettua tiedostoa jossa 105 lisäystä ja 103 poistoa

Näytä tiedosto

@@ -0,0 +1,61 @@
if MACH_LOONGSON32
choice
prompt "Machine Type"
config LOONGSON1_LS1B
bool "Loongson LS1B board"
select CEVT_R4K if !MIPS_EXTERNAL_TIMER
select CSRC_R4K if !MIPS_EXTERNAL_TIMER
select SYS_HAS_CPU_LOONGSON1B
select DMA_NONCOHERENT
select BOOT_ELF32
select IRQ_MIPS_CPU
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_MIPS16
select SYS_HAS_EARLY_PRINTK
select USE_GENERIC_EARLY_PRINTK_8250
select COMMON_CLK
endchoice
menuconfig CEVT_CSRC_LS1X
bool "Use PWM Timer for clockevent/clocksource"
select MIPS_EXTERNAL_TIMER
depends on CPU_LOONGSON1
help
This option changes the default clockevent/clocksource to PWM Timer,
and is required by Loongson1 CPUFreq support.
If unsure, say N.
choice
prompt "Select clockevent/clocksource"
depends on CEVT_CSRC_LS1X
default TIMER_USE_PWM0
config TIMER_USE_PWM0
bool "Use PWM Timer 0"
help
Use PWM Timer 0 as the default clockevent/clocksourcer.
config TIMER_USE_PWM1
bool "Use PWM Timer 1"
help
Use PWM Timer 1 as the default clockevent/clocksourcer.
config TIMER_USE_PWM2
bool "Use PWM Timer 2"
help
Use PWM Timer 2 as the default clockevent/clocksourcer.
config TIMER_USE_PWM3
bool "Use PWM Timer 3"
help
Use PWM Timer 3 as the default clockevent/clocksourcer.
endchoice
endif # MACH_LOONGSON32

Näytä tiedosto

@@ -0,0 +1,11 @@
#
# Common code for all Loongson 1 based systems
#
obj-$(CONFIG_MACH_LOONGSON32) += common/
#
# Loongson LS1B board
#
obj-$(CONFIG_LOONGSON1_LS1B) += ls1b/

Näytä tiedosto

@@ -0,0 +1,7 @@
cflags-$(CONFIG_CPU_LOONGSON1) += \
$(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
-Wa,-mips32r2 -Wa,--trap
platform-$(CONFIG_MACH_LOONGSON32) += loongson32/
cflags-$(CONFIG_MACH_LOONGSON32) += -I$(srctree)/arch/mips/include/asm/mach-loongson32
load-$(CONFIG_LOONGSON1_LS1B) += 0xffffffff80100000

Näytä tiedosto

@@ -0,0 +1,5 @@
#
# Makefile for common code of loongson1 based machines.
#
obj-y += time.o irq.o platform.o prom.o reset.o setup.o

Näytä tiedosto

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
*
* 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.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/irq_cpu.h>
#include <loongson1.h>
#include <irq.h>
#define LS1X_INTC_REG(n, x) \
((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x)))
#define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0)
#define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4)
#define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8)
#define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc)
#define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10)
#define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14)
static void ls1x_irq_ack(struct irq_data *d)
{
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
| (1 << bit), LS1X_INTC_INTCLR(n));
}
static void ls1x_irq_mask(struct irq_data *d)
{
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
& ~(1 << bit), LS1X_INTC_INTIEN(n));
}
static void ls1x_irq_mask_ack(struct irq_data *d)
{
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
& ~(1 << bit), LS1X_INTC_INTIEN(n));
__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n))
| (1 << bit), LS1X_INTC_INTCLR(n));
}
static void ls1x_irq_unmask(struct irq_data *d)
{
unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f;
unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5;
__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n))
| (1 << bit), LS1X_INTC_INTIEN(n));
}
static struct irq_chip ls1x_irq_chip = {
.name = "LS1X-INTC",
.irq_ack = ls1x_irq_ack,
.irq_mask = ls1x_irq_mask,
.irq_mask_ack = ls1x_irq_mask_ack,
.irq_unmask = ls1x_irq_unmask,
};
static void ls1x_irq_dispatch(int n)
{
u32 int_status, irq;
/* Get pending sources, masked by current enables */
int_status = __raw_readl(LS1X_INTC_INTISR(n)) &
__raw_readl(LS1X_INTC_INTIEN(n));
if (int_status) {
irq = LS1X_IRQ(n, __ffs(int_status));
do_IRQ(irq);
}
}
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending;
pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & CAUSEF_IP7)
do_IRQ(TIMER_IRQ);
else if (pending & CAUSEF_IP2)
ls1x_irq_dispatch(0); /* INT0 */
else if (pending & CAUSEF_IP3)
ls1x_irq_dispatch(1); /* INT1 */
else if (pending & CAUSEF_IP4)
ls1x_irq_dispatch(2); /* INT2 */
else if (pending & CAUSEF_IP5)
ls1x_irq_dispatch(3); /* INT3 */
else if (pending & CAUSEF_IP6)
ls1x_irq_dispatch(4); /* INT4 */
else
spurious_interrupt();
}
struct irqaction cascade_irqaction = {
.handler = no_action,
.name = "cascade",
.flags = IRQF_NO_THREAD,
};
static void __init ls1x_irq_init(int base)
{
int n;
/* Disable interrupts and clear pending,
* setup all IRQs as high level triggered
*/
for (n = 0; n < 4; n++) {
__raw_writel(0x0, LS1X_INTC_INTIEN(n));
__raw_writel(0xffffffff, LS1X_INTC_INTCLR(n));
__raw_writel(0xffffffff, LS1X_INTC_INTPOL(n));
/* set DMA0, DMA1 and DMA2 to edge trigger */
__raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n));
}
for (n = base; n < LS1X_IRQS; n++) {
irq_set_chip_and_handler(n, &ls1x_irq_chip,
handle_level_irq);
}
setup_irq(INT0_IRQ, &cascade_irqaction);
setup_irq(INT1_IRQ, &cascade_irqaction);
setup_irq(INT2_IRQ, &cascade_irqaction);
setup_irq(INT3_IRQ, &cascade_irqaction);
}
void __init arch_init_irq(void)
{
mips_cpu_irq_init();
ls1x_irq_init(LS1X_IRQ_BASE);
}

Näytä tiedosto

@@ -0,0 +1,234 @@
/*
* Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
*
* 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.
*/
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/phy.h>
#include <linux/serial_8250.h>
#include <linux/stmmac.h>
#include <linux/usb/ehci_pdriver.h>
#include <asm-generic/sizes.h>
#include <cpufreq.h>
#include <loongson1.h>
/* 8250/16550 compatible UART */
#define LS1X_UART(_id) \
{ \
.mapbase = LS1X_UART ## _id ## _BASE, \
.irq = LS1X_UART ## _id ## _IRQ, \
.iotype = UPIO_MEM, \
.flags = UPF_IOREMAP | UPF_FIXED_TYPE, \
.type = PORT_16550A, \
}
static struct plat_serial8250_port ls1x_serial8250_pdata[] = {
LS1X_UART(0),
LS1X_UART(1),
LS1X_UART(2),
LS1X_UART(3),
{},
};
struct platform_device ls1x_uart_pdev = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = ls1x_serial8250_pdata,
},
};
void __init ls1x_serial_setup(struct platform_device *pdev)
{
struct clk *clk;
struct plat_serial8250_port *p;
clk = clk_get(&pdev->dev, pdev->name);
if (IS_ERR(clk)) {
pr_err("unable to get %s clock, err=%ld",
pdev->name, PTR_ERR(clk));
return;
}
clk_prepare_enable(clk);
for (p = pdev->dev.platform_data; p->flags != 0; ++p)
p->uartclk = clk_get_rate(clk);
}
/* CPUFreq */
static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = {
.clk_name = "cpu_clk",
.osc_clk_name = "osc_33m_clk",
.max_freq = 266 * 1000,
.min_freq = 33 * 1000,
};
struct platform_device ls1x_cpufreq_pdev = {
.name = "ls1x-cpufreq",
.dev = {
.platform_data = &ls1x_cpufreq_pdata,
},
};
/* Synopsys Ethernet GMAC */
static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
.phy_mask = 0,
};
static struct stmmac_dma_cfg ls1x_eth_dma_cfg = {
.pbl = 1,
};
int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
{
struct plat_stmmacenet_data *plat_dat = NULL;
u32 val;
val = __raw_readl(LS1X_MUX_CTRL1);
plat_dat = dev_get_platdata(&pdev->dev);
if (plat_dat->bus_id) {
__raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
GMAC1_USE_UART0, LS1X_MUX_CTRL0);
switch (plat_dat->interface) {
case PHY_INTERFACE_MODE_RGMII:
val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
break;
case PHY_INTERFACE_MODE_MII:
val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
break;
default:
pr_err("unsupported mii mode %d\n",
plat_dat->interface);
return -ENOTSUPP;
}
val &= ~GMAC1_SHUT;
} else {
switch (plat_dat->interface) {
case PHY_INTERFACE_MODE_RGMII:
val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
break;
case PHY_INTERFACE_MODE_MII:
val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
break;
default:
pr_err("unsupported mii mode %d\n",
plat_dat->interface);
return -ENOTSUPP;
}
val &= ~GMAC0_SHUT;
}
__raw_writel(val, LS1X_MUX_CTRL1);
return 0;
}
static struct plat_stmmacenet_data ls1x_eth0_pdata = {
.bus_id = 0,
.phy_addr = -1,
.interface = PHY_INTERFACE_MODE_MII,
.mdio_bus_data = &ls1x_mdio_bus_data,
.dma_cfg = &ls1x_eth_dma_cfg,
.has_gmac = 1,
.tx_coe = 1,
.init = ls1x_eth_mux_init,
};
static struct resource ls1x_eth0_resources[] = {
[0] = {
.start = LS1X_GMAC0_BASE,
.end = LS1X_GMAC0_BASE + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "macirq",
.start = LS1X_GMAC0_IRQ,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device ls1x_eth0_pdev = {
.name = "stmmaceth",
.id = 0,
.num_resources = ARRAY_SIZE(ls1x_eth0_resources),
.resource = ls1x_eth0_resources,
.dev = {
.platform_data = &ls1x_eth0_pdata,
},
};
static struct plat_stmmacenet_data ls1x_eth1_pdata = {
.bus_id = 1,
.phy_addr = -1,
.interface = PHY_INTERFACE_MODE_MII,
.mdio_bus_data = &ls1x_mdio_bus_data,
.dma_cfg = &ls1x_eth_dma_cfg,
.has_gmac = 1,
.tx_coe = 1,
.init = ls1x_eth_mux_init,
};
static struct resource ls1x_eth1_resources[] = {
[0] = {
.start = LS1X_GMAC1_BASE,
.end = LS1X_GMAC1_BASE + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.name = "macirq",
.start = LS1X_GMAC1_IRQ,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device ls1x_eth1_pdev = {
.name = "stmmaceth",
.id = 1,
.num_resources = ARRAY_SIZE(ls1x_eth1_resources),
.resource = ls1x_eth1_resources,
.dev = {
.platform_data = &ls1x_eth1_pdata,
},
};
/* USB EHCI */
static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
static struct resource ls1x_ehci_resources[] = {
[0] = {
.start = LS1X_EHCI_BASE,
.end = LS1X_EHCI_BASE + SZ_32K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = LS1X_EHCI_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct usb_ehci_pdata ls1x_ehci_pdata = {
};
struct platform_device ls1x_ehci_pdev = {
.name = "ehci-platform",
.id = -1,
.num_resources = ARRAY_SIZE(ls1x_ehci_resources),
.resource = ls1x_ehci_resources,
.dev = {
.dma_mask = &ls1x_ehci_dmamask,
.platform_data = &ls1x_ehci_pdata,
},
};
/* Real Time Clock */
struct platform_device ls1x_rtc_pdev = {
.name = "ls1x-rtc",
.id = -1,
};

Näytä tiedosto

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
*
* Modified from arch/mips/pnx833x/common/prom.c.
*
* 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.
*/
#include <linux/serial_reg.h>
#include <asm/bootinfo.h>
#include <loongson1.h>
#include <prom.h>
int prom_argc;
char **prom_argv, **prom_envp;
unsigned long memsize, highmemsize;
char *prom_getenv(char *envname)
{
char **env = prom_envp;
int i;
i = strlen(envname);
while (*env) {
if (strncmp(envname, *env, i) == 0 && *(*env + i) == '=')
return *env + i + 1;
env++;
}
return 0;
}
static inline unsigned long env_or_default(char *env, unsigned long dfl)
{
char *str = prom_getenv(env);
return str ? simple_strtol(str, 0, 0) : dfl;
}
void __init prom_init_cmdline(void)
{
char *c = &(arcs_cmdline[0]);
int i;
for (i = 1; i < prom_argc; i++) {
strcpy(c, prom_argv[i]);
c += strlen(prom_argv[i]);
if (i < prom_argc - 1)
*c++ = ' ';
}
*c = 0;
}
void __init prom_init(void)
{
void __iomem *uart_base;
prom_argc = fw_arg0;
prom_argv = (char **)fw_arg1;
prom_envp = (char **)fw_arg2;
prom_init_cmdline();
memsize = env_or_default("memsize", DEFAULT_MEMSIZE);
highmemsize = env_or_default("highmemsize", 0x0);
if (strstr(arcs_cmdline, "console=ttyS3"))
uart_base = ioremap_nocache(LS1X_UART3_BASE, 0x0f);
else if (strstr(arcs_cmdline, "console=ttyS2"))
uart_base = ioremap_nocache(LS1X_UART2_BASE, 0x0f);
else if (strstr(arcs_cmdline, "console=ttyS1"))
uart_base = ioremap_nocache(LS1X_UART1_BASE, 0x0f);
else
uart_base = ioremap_nocache(LS1X_UART0_BASE, 0x0f);
setup_8250_early_printk_port((unsigned long)uart_base, 0, 0);
}
void __init prom_free_prom_memory(void)
{
}

Näytä tiedosto

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
*
* 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.
*/
#include <linux/io.h>
#include <linux/pm.h>
#include <asm/idle.h>
#include <asm/reboot.h>
#include <loongson1.h>
static void __iomem *wdt_base;
static void ls1x_halt(void)
{
while (1) {
if (cpu_wait)
cpu_wait();
}
}
static void ls1x_restart(char *command)
{
__raw_writel(0x1, wdt_base + WDT_EN);
__raw_writel(0x1, wdt_base + WDT_TIMER);
__raw_writel(0x1, wdt_base + WDT_SET);
ls1x_halt();
}
static void ls1x_power_off(void)
{
ls1x_halt();
}
static int __init ls1x_reboot_setup(void)
{
wdt_base = ioremap_nocache(LS1X_WDT_BASE, 0x0f);
if (!wdt_base)
panic("Failed to remap watchdog registers");
_machine_restart = ls1x_restart;
_machine_halt = ls1x_halt;
pm_power_off = ls1x_power_off;
return 0;
}
arch_initcall(ls1x_reboot_setup);

Näytä tiedosto

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
*
* 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.
*/
#include <asm/bootinfo.h>
#include <prom.h>
void __init plat_mem_setup(void)
{
add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
}
const char *get_system_type(void)
{
unsigned int processor_id = (&current_cpu_data)->processor_id;
switch (processor_id & PRID_REV_MASK) {
case PRID_REV_LOONGSON1B:
return "LOONGSON LS1B";
default:
return "LOONGSON (unknown)";
}
}

Näytä tiedosto

@@ -0,0 +1,226 @@
/*
* Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com>
*
* 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.
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <asm/time.h>
#include <loongson1.h>
#include <platform.h>
#ifdef CONFIG_CEVT_CSRC_LS1X
#if defined(CONFIG_TIMER_USE_PWM1)
#define LS1X_TIMER_BASE LS1X_PWM1_BASE
#define LS1X_TIMER_IRQ LS1X_PWM1_IRQ
#elif defined(CONFIG_TIMER_USE_PWM2)
#define LS1X_TIMER_BASE LS1X_PWM2_BASE
#define LS1X_TIMER_IRQ LS1X_PWM2_IRQ
#elif defined(CONFIG_TIMER_USE_PWM3)
#define LS1X_TIMER_BASE LS1X_PWM3_BASE
#define LS1X_TIMER_IRQ LS1X_PWM3_IRQ
#else
#define LS1X_TIMER_BASE LS1X_PWM0_BASE
#define LS1X_TIMER_IRQ LS1X_PWM0_IRQ
#endif
DEFINE_RAW_SPINLOCK(ls1x_timer_lock);
static void __iomem *timer_base;
static uint32_t ls1x_jiffies_per_tick;
static inline void ls1x_pwmtimer_set_period(uint32_t period)
{
__raw_writel(period, timer_base + PWM_HRC);
__raw_writel(period, timer_base + PWM_LRC);
}
static inline void ls1x_pwmtimer_restart(void)
{
__raw_writel(0x0, timer_base + PWM_CNT);
__raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL);
}
void __init ls1x_pwmtimer_init(void)
{
timer_base = ioremap(LS1X_TIMER_BASE, 0xf);
if (!timer_base)
panic("Failed to remap timer registers");
ls1x_jiffies_per_tick = DIV_ROUND_CLOSEST(mips_hpt_frequency, HZ);
ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick);
ls1x_pwmtimer_restart();
}
static cycle_t ls1x_clocksource_read(struct clocksource *cs)
{
unsigned long flags;
int count;
u32 jifs;
static int old_count;
static u32 old_jifs;
raw_spin_lock_irqsave(&ls1x_timer_lock, flags);
/*
* Although our caller may have the read side of xtime_lock,
* this is now a seqlock, and we are cheating in this routine
* by having side effects on state that we cannot undo if
* there is a collision on the seqlock and our caller has to
* retry. (Namely, old_jifs and old_count.) So we must treat
* jiffies as volatile despite the lock. We read jiffies
* before latching the timer count to guarantee that although
* the jiffies value might be older than the count (that is,
* the counter may underflow between the last point where
* jiffies was incremented and the point where we latch the
* count), it cannot be newer.
*/
jifs = jiffies;
/* read the count */
count = __raw_readl(timer_base + PWM_CNT);
/*
* It's possible for count to appear to go the wrong way for this
* reason:
*
* The timer counter underflows, but we haven't handled the resulting
* interrupt and incremented jiffies yet.
*
* Previous attempts to handle these cases intelligently were buggy, so
* we just do the simple thing now.
*/
if (count < old_count && jifs == old_jifs)
count = old_count;
old_count = count;
old_jifs = jifs;
raw_spin_unlock_irqrestore(&ls1x_timer_lock, flags);
return (cycle_t) (jifs * ls1x_jiffies_per_tick) + count;
}
static struct clocksource ls1x_clocksource = {
.name = "ls1x-pwmtimer",
.read = ls1x_clocksource_read,
.mask = CLOCKSOURCE_MASK(24),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static irqreturn_t ls1x_clockevent_isr(int irq, void *devid)
{
struct clock_event_device *cd = devid;
ls1x_pwmtimer_restart();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static void ls1x_clockevent_set_mode(enum clock_event_mode mode,
struct clock_event_device *cd)
{
raw_spin_lock(&ls1x_timer_lock);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick);
ls1x_pwmtimer_restart();
case CLOCK_EVT_MODE_RESUME:
__raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL);
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_SHUTDOWN:
__raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN,
timer_base + PWM_CTRL);
break;
default:
break;
}
raw_spin_unlock(&ls1x_timer_lock);
}
static int ls1x_clockevent_set_next(unsigned long evt,
struct clock_event_device *cd)
{
raw_spin_lock(&ls1x_timer_lock);
ls1x_pwmtimer_set_period(evt);
ls1x_pwmtimer_restart();
raw_spin_unlock(&ls1x_timer_lock);
return 0;
}
static struct clock_event_device ls1x_clockevent = {
.name = "ls1x-pwmtimer",
.features = CLOCK_EVT_FEAT_PERIODIC,
.rating = 300,
.irq = LS1X_TIMER_IRQ,
.set_next_event = ls1x_clockevent_set_next,
.set_mode = ls1x_clockevent_set_mode,
};
static struct irqaction ls1x_pwmtimer_irqaction = {
.name = "ls1x-pwmtimer",
.handler = ls1x_clockevent_isr,
.dev_id = &ls1x_clockevent,
.flags = IRQF_PERCPU | IRQF_TIMER,
};
static void __init ls1x_time_init(void)
{
struct clock_event_device *cd = &ls1x_clockevent;
int ret;
if (!mips_hpt_frequency)
panic("Invalid timer clock rate");
ls1x_pwmtimer_init();
clockevent_set_clock(cd, mips_hpt_frequency);
cd->max_delta_ns = clockevent_delta2ns(0xffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0x000300, cd);
cd->cpumask = cpumask_of(smp_processor_id());
clockevents_register_device(cd);
ls1x_clocksource.rating = 200 + mips_hpt_frequency / 10000000;
ret = clocksource_register_hz(&ls1x_clocksource, mips_hpt_frequency);
if (ret)
panic(KERN_ERR "Failed to register clocksource: %d\n", ret);
setup_irq(LS1X_TIMER_IRQ, &ls1x_pwmtimer_irqaction);
}
#endif /* CONFIG_CEVT_CSRC_LS1X */
void __init plat_time_init(void)
{
struct clk *clk = NULL;
/* initialize LS1X clocks */
ls1x_clk_init();
#ifdef CONFIG_CEVT_CSRC_LS1X
/* setup LS1X PWM timer */
clk = clk_get(NULL, "ls1x_pwmtimer");
if (IS_ERR(clk))
panic("unable to get timer clock, err=%ld", PTR_ERR(clk));
mips_hpt_frequency = clk_get_rate(clk);
ls1x_time_init();
#else
/* setup mips r4k timer */
clk = clk_get(NULL, "cpu_clk");
if (IS_ERR(clk))
panic("unable to get cpu clock, err=%ld", PTR_ERR(clk));
mips_hpt_frequency = clk_get_rate(clk) / 2;
#endif /* CONFIG_CEVT_CSRC_LS1X */
}

Näytä tiedosto

@@ -0,0 +1,5 @@
#
# Makefile for loongson1B based machines.
#
obj-y += board.o

Näytä tiedosto

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
*
* 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.
*/
#include <platform.h>
static struct platform_device *ls1b_platform_devices[] __initdata = {
&ls1x_uart_pdev,
&ls1x_cpufreq_pdev,
&ls1x_eth0_pdev,
&ls1x_eth1_pdev,
&ls1x_ehci_pdev,
&ls1x_rtc_pdev,
};
static int __init ls1b_platform_init(void)
{
int err;
ls1x_serial_setup(&ls1x_uart_pdev);
err = platform_add_devices(ls1b_platform_devices,
ARRAY_SIZE(ls1b_platform_devices));
return err;
}
arch_initcall(ls1b_platform_init);