mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-04-21 12:27:27 +03:00
[lantiq] cleanup patches
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@32953 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
11
target/linux/lantiq/files/arch/mips/lantiq/falcon/Kconfig
Normal file
11
target/linux/lantiq/files/arch/mips/lantiq/falcon/Kconfig
Normal file
@@ -0,0 +1,11 @@
|
||||
if SOC_FALCON
|
||||
|
||||
menu "MIPS Machine"
|
||||
|
||||
config LANTIQ_MACH_EASY98000
|
||||
bool "Easy98000"
|
||||
default y
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-y := prom.o reset.o sysctrl.o devices.o gpio.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
152
target/linux/lantiq/files/arch/mips/lantiq/falcon/devices.c
Normal file
152
target/linux/lantiq/files/arch/mips/lantiq/falcon/devices.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
/* nand flash */
|
||||
/* address lines used for NAND control signals */
|
||||
#define NAND_ADDR_ALE 0x10000
|
||||
#define NAND_ADDR_CLE 0x20000
|
||||
/* Ready/Busy Status */
|
||||
#define MODCON_STS 0x0002
|
||||
/* Ready/Busy Status Edge */
|
||||
#define MODCON_STSEDGE 0x0004
|
||||
|
||||
static const char *part_probes[] = { "cmdlinepart", NULL };
|
||||
|
||||
static int
|
||||
falcon_nand_ready(struct mtd_info *mtd)
|
||||
{
|
||||
u32 modcon = ltq_ebu_r32(LTQ_EBU_MODCON);
|
||||
|
||||
return (((modcon & (MODCON_STS | MODCON_STSEDGE)) ==
|
||||
(MODCON_STS | MODCON_STSEDGE)));
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
nandaddr &= ~(NAND_ADDR_ALE | NAND_ADDR_CLE);
|
||||
|
||||
if (ctrl & NAND_CLE)
|
||||
nandaddr |= NAND_ADDR_CLE;
|
||||
if (ctrl & NAND_ALE)
|
||||
nandaddr |= NAND_ADDR_ALE;
|
||||
|
||||
this->IO_ADDR_W = (void __iomem *) nandaddr;
|
||||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
}
|
||||
|
||||
static struct platform_nand_data falcon_flash_nand_data = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.chip_delay = 25,
|
||||
.part_probe_types = part_probes,
|
||||
},
|
||||
.ctrl = {
|
||||
.cmd_ctrl = falcon_hwcontrol,
|
||||
.dev_ready = falcon_nand_ready,
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource ltq_nand_res =
|
||||
MEM_RES("nand", LTQ_FLASH_START, LTQ_FLASH_MAX);
|
||||
|
||||
static struct platform_device ltq_flash_nand = {
|
||||
.name = "gen_nand",
|
||||
.id = -1,
|
||||
.num_resources = 1,
|
||||
.resource = <q_nand_res,
|
||||
.dev = {
|
||||
.platform_data = &falcon_flash_nand_data,
|
||||
},
|
||||
};
|
||||
|
||||
void __init
|
||||
falcon_register_nand(void)
|
||||
{
|
||||
platform_device_register(<q_flash_nand);
|
||||
}
|
||||
|
||||
/* gpio */
|
||||
#define DECLARE_GPIO_RES(port) \
|
||||
static struct resource falcon_gpio ## port ## _res[] = { \
|
||||
MEM_RES("gpio"#port, LTQ_GPIO ## port ## _BASE_ADDR, \
|
||||
LTQ_GPIO ## port ## _SIZE), \
|
||||
MEM_RES("padctrl"#port, LTQ_PADCTRL ## port ## _BASE_ADDR, \
|
||||
LTQ_PADCTRL ## port ## _SIZE), \
|
||||
IRQ_RES("gpio_mux"#port, FALCON_IRQ_GPIO_P ## port) \
|
||||
}
|
||||
DECLARE_GPIO_RES(0);
|
||||
DECLARE_GPIO_RES(1);
|
||||
DECLARE_GPIO_RES(2);
|
||||
DECLARE_GPIO_RES(3);
|
||||
DECLARE_GPIO_RES(4);
|
||||
|
||||
void __init
|
||||
falcon_register_gpio(void)
|
||||
{
|
||||
platform_device_register_simple("falcon_gpio", 0,
|
||||
falcon_gpio0_res, ARRAY_SIZE(falcon_gpio0_res));
|
||||
platform_device_register_simple("falcon_gpio", 1,
|
||||
falcon_gpio1_res, ARRAY_SIZE(falcon_gpio1_res));
|
||||
platform_device_register_simple("falcon_gpio", 2,
|
||||
falcon_gpio2_res, ARRAY_SIZE(falcon_gpio2_res));
|
||||
}
|
||||
|
||||
void __init
|
||||
falcon_register_gpio_extra(void)
|
||||
{
|
||||
platform_device_register_simple("falcon_gpio", 3,
|
||||
falcon_gpio3_res, ARRAY_SIZE(falcon_gpio3_res));
|
||||
platform_device_register_simple("falcon_gpio", 4,
|
||||
falcon_gpio4_res, ARRAY_SIZE(falcon_gpio4_res));
|
||||
}
|
||||
|
||||
/* spi flash */
|
||||
static struct platform_device ltq_spi = {
|
||||
.name = "falcon_spi",
|
||||
.num_resources = 0,
|
||||
};
|
||||
|
||||
void __init
|
||||
falcon_register_spi_flash(struct spi_board_info *data)
|
||||
{
|
||||
spi_register_board_info(data, 1);
|
||||
platform_device_register(<q_spi);
|
||||
}
|
||||
|
||||
/* i2c */
|
||||
static struct resource falcon_i2c_resources[] = {
|
||||
MEM_RES("i2c", GPON_I2C_BASE, GPON_I2C_SIZE),
|
||||
IRQ_RES(i2c_lb, FALCON_IRQ_I2C_LBREQ),
|
||||
IRQ_RES(i2c_b, FALCON_IRQ_I2C_BREQ),
|
||||
IRQ_RES(i2c_err, FALCON_IRQ_I2C_I2C_ERR),
|
||||
IRQ_RES(i2c_p, FALCON_IRQ_I2C_I2C_P),
|
||||
};
|
||||
|
||||
void __init
|
||||
falcon_register_i2c(void)
|
||||
{
|
||||
platform_device_register_simple("i2c-falcon", 0,
|
||||
falcon_i2c_resources, ARRAY_SIZE(falcon_i2c_resources));
|
||||
}
|
||||
25
target/linux/lantiq/files/arch/mips/lantiq/falcon/devices.h
Normal file
25
target/linux/lantiq/files/arch/mips/lantiq/falcon/devices.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#ifndef _FALCON_DEVICES_H__
|
||||
#define _FALCON_DEVICES_H__
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
|
||||
#include "../devices.h"
|
||||
|
||||
extern void falcon_register_nand(void);
|
||||
extern void falcon_register_gpio(void);
|
||||
extern void falcon_register_gpio_extra(void);
|
||||
extern void falcon_register_spi_flash(struct spi_board_info *data);
|
||||
extern void falcon_register_i2c(void);
|
||||
|
||||
#endif
|
||||
409
target/linux/lantiq/files/arch/mips/lantiq/falcon/gpio.c
Normal file
409
target/linux/lantiq/files/arch/mips/lantiq/falcon/gpio.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
/* Multiplexer Control Register */
|
||||
#define LTQ_PADC_MUX(x) (x * 0x4)
|
||||
/* Pad Control Availability Register */
|
||||
#define LTQ_PADC_AVAIL 0x000000F0
|
||||
|
||||
/* Data Output Register */
|
||||
#define LTQ_GPIO_OUT 0x00000000
|
||||
/* Data Input Register */
|
||||
#define LTQ_GPIO_IN 0x00000004
|
||||
/* Direction Register */
|
||||
#define LTQ_GPIO_DIR 0x00000008
|
||||
/* External Interrupt Control Register 0 */
|
||||
#define LTQ_GPIO_EXINTCR0 0x00000018
|
||||
/* External Interrupt Control Register 1 */
|
||||
#define LTQ_GPIO_EXINTCR1 0x0000001C
|
||||
/* IRN Capture Register */
|
||||
#define LTQ_GPIO_IRNCR 0x00000020
|
||||
/* IRN Interrupt Configuration Register */
|
||||
#define LTQ_GPIO_IRNCFG 0x0000002C
|
||||
/* IRN Interrupt Enable Set Register */
|
||||
#define LTQ_GPIO_IRNRNSET 0x00000030
|
||||
/* IRN Interrupt Enable Clear Register */
|
||||
#define LTQ_GPIO_IRNENCLR 0x00000034
|
||||
/* Output Set Register */
|
||||
#define LTQ_GPIO_OUTSET 0x00000040
|
||||
/* Output Cler Register */
|
||||
#define LTQ_GPIO_OUTCLR 0x00000044
|
||||
/* Direction Clear Register */
|
||||
#define LTQ_GPIO_DIRSET 0x00000048
|
||||
/* Direction Set Register */
|
||||
#define LTQ_GPIO_DIRCLR 0x0000004C
|
||||
|
||||
/* turn a gpio_chip into a falcon_gpio_port */
|
||||
#define ctop(c) container_of(c, struct falcon_gpio_port, gpio_chip)
|
||||
/* turn a irq_data into a falcon_gpio_port */
|
||||
#define itop(i) ((struct falcon_gpio_port *) irq_get_chip_data(i->irq))
|
||||
|
||||
#define ltq_pad_r32(p, reg) ltq_r32(p->pad + reg)
|
||||
#define ltq_pad_w32(p, val, reg) ltq_w32(val, p->pad + reg)
|
||||
#define ltq_pad_w32_mask(c, clear, set, reg) \
|
||||
ltq_pad_w32(c, (ltq_pad_r32(c, reg) & ~(clear)) | (set), reg)
|
||||
|
||||
#define ltq_port_r32(p, reg) ltq_r32(p->port + reg)
|
||||
#define ltq_port_w32(p, val, reg) ltq_w32(val, p->port + reg)
|
||||
#define ltq_port_w32_mask(p, clear, set, reg) \
|
||||
ltq_port_w32(p, (ltq_port_r32(p, reg) & ~(clear)) | (set), reg)
|
||||
|
||||
#define MAX_PORTS 5
|
||||
#define PINS_PER_PORT 32
|
||||
|
||||
struct falcon_gpio_port {
|
||||
struct gpio_chip gpio_chip;
|
||||
void __iomem *pad;
|
||||
void __iomem *port;
|
||||
unsigned int irq_base;
|
||||
unsigned int chained_irq;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static struct falcon_gpio_port ltq_gpio_port[MAX_PORTS];
|
||||
|
||||
int gpio_to_irq(unsigned int gpio)
|
||||
{
|
||||
return __gpio_to_irq(gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_to_irq);
|
||||
|
||||
int ltq_gpio_mux_set(unsigned int pin, unsigned int mux)
|
||||
{
|
||||
int port = pin / 100;
|
||||
int offset = pin % 100;
|
||||
struct falcon_gpio_port *gpio_port;
|
||||
|
||||
if ((offset >= PINS_PER_PORT) || (port >= MAX_PORTS))
|
||||
return -EINVAL;
|
||||
|
||||
gpio_port = <q_gpio_port[port];
|
||||
ltq_pad_w32(gpio_port, mux & 0x3, LTQ_PADC_MUX(offset));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ltq_gpio_mux_set);
|
||||
|
||||
int ltq_gpio_request(struct device *dev, unsigned int pin, unsigned int mux,
|
||||
unsigned int dir, const char *name)
|
||||
{
|
||||
int port = pin / 100;
|
||||
int offset = pin % 100;
|
||||
|
||||
if (offset >= PINS_PER_PORT || port >= MAX_PORTS)
|
||||
return -EINVAL;
|
||||
|
||||
if (devm_gpio_request(dev, pin, name)) {
|
||||
pr_err("failed to setup lantiq gpio: %s\n", name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (dir)
|
||||
gpio_direction_output(pin, 1);
|
||||
else
|
||||
gpio_direction_input(pin);
|
||||
|
||||
return ltq_gpio_mux_set(pin, mux);
|
||||
}
|
||||
EXPORT_SYMBOL(ltq_gpio_request);
|
||||
|
||||
static int
|
||||
falcon_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_DIRCLR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
if (value)
|
||||
ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_OUTSET);
|
||||
else
|
||||
ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_OUTCLR);
|
||||
}
|
||||
|
||||
static int
|
||||
falcon_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
falcon_gpio_set(chip, offset, value);
|
||||
ltq_port_w32(ctop(chip), 1 << offset, LTQ_GPIO_DIRSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
falcon_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
if ((ltq_port_r32(ctop(chip), LTQ_GPIO_DIR) >> offset) & 1)
|
||||
return (ltq_port_r32(ctop(chip), LTQ_GPIO_OUT) >> offset) & 1;
|
||||
else
|
||||
return (ltq_port_r32(ctop(chip), LTQ_GPIO_IN) >> offset) & 1;
|
||||
}
|
||||
|
||||
static int
|
||||
falcon_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
if ((ltq_pad_r32(ctop(chip), LTQ_PADC_AVAIL) >> offset) & 1) {
|
||||
if (ltq_pad_r32(ctop(chip), LTQ_PADC_MUX(offset)) > 1)
|
||||
return -EBUSY;
|
||||
/* switch on gpio function */
|
||||
ltq_pad_w32(ctop(chip), 1, LTQ_PADC_MUX(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
if ((ltq_pad_r32(ctop(chip), LTQ_PADC_AVAIL) >> offset) & 1) {
|
||||
if (ltq_pad_r32(ctop(chip), LTQ_PADC_MUX(offset)) > 1)
|
||||
return;
|
||||
/* switch off gpio function */
|
||||
ltq_pad_w32(ctop(chip), 0, LTQ_PADC_MUX(offset));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
falcon_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return ctop(chip)->irq_base + offset;
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_disable_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int offset = d->irq - itop(d)->irq_base;
|
||||
|
||||
ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNENCLR);
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_enable_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int offset = d->irq - itop(d)->irq_base;
|
||||
|
||||
if (!ltq_pad_r32(itop(d), LTQ_PADC_MUX(offset)) < 1)
|
||||
/* switch on gpio function */
|
||||
ltq_pad_w32(itop(d), 1, LTQ_PADC_MUX(offset));
|
||||
|
||||
ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNRNSET);
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_ack_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int offset = d->irq - itop(d)->irq_base;
|
||||
|
||||
ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNCR);
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_mask_and_ack_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int offset = d->irq - itop(d)->irq_base;
|
||||
|
||||
ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNENCLR);
|
||||
ltq_port_w32(itop(d), 1 << offset, LTQ_GPIO_IRNCR);
|
||||
}
|
||||
|
||||
static struct irq_chip falcon_gpio_irq_chip;
|
||||
static int
|
||||
falcon_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
unsigned int offset = d->irq - itop(d)->irq_base;
|
||||
unsigned int mask = 1 << offset;
|
||||
|
||||
if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE)
|
||||
return 0;
|
||||
|
||||
if ((type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) != 0) {
|
||||
/* level triggered */
|
||||
ltq_port_w32_mask(itop(d), 0, mask, LTQ_GPIO_IRNCFG);
|
||||
irq_set_chip_and_handler_name(d->irq,
|
||||
&falcon_gpio_irq_chip, handle_level_irq, "mux");
|
||||
} else {
|
||||
/* edge triggered */
|
||||
ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_IRNCFG);
|
||||
irq_set_chip_and_handler_name(d->irq,
|
||||
&falcon_gpio_irq_chip, handle_simple_irq, "mux");
|
||||
}
|
||||
|
||||
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
|
||||
ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_EXINTCR0);
|
||||
ltq_port_w32_mask(itop(d), 0, mask, LTQ_GPIO_EXINTCR1);
|
||||
} else {
|
||||
if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) != 0)
|
||||
/* positive logic: rising edge, high level */
|
||||
ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_EXINTCR0);
|
||||
else
|
||||
/* negative logic: falling edge, low level */
|
||||
ltq_port_w32_mask(itop(d), 0, mask, LTQ_GPIO_EXINTCR0);
|
||||
ltq_port_w32_mask(itop(d), mask, 0, LTQ_GPIO_EXINTCR1);
|
||||
}
|
||||
|
||||
return gpio_direction_input(itop(d)->gpio_chip.base + offset);
|
||||
}
|
||||
|
||||
static void
|
||||
falcon_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct falcon_gpio_port *gpio_port = irq_desc_get_handler_data(desc);
|
||||
unsigned long irncr;
|
||||
int offset;
|
||||
|
||||
/* acknowledge interrupt */
|
||||
irncr = ltq_port_r32(gpio_port, LTQ_GPIO_IRNCR);
|
||||
ltq_port_w32(gpio_port, irncr, LTQ_GPIO_IRNCR);
|
||||
|
||||
desc->irq_data.chip->irq_ack(&desc->irq_data);
|
||||
|
||||
for_each_set_bit(offset, &irncr, gpio_port->gpio_chip.ngpio)
|
||||
generic_handle_irq(gpio_port->irq_base + offset);
|
||||
}
|
||||
|
||||
static struct irq_chip falcon_gpio_irq_chip = {
|
||||
.name = "gpio_irq_mux",
|
||||
.irq_mask = falcon_gpio_disable_irq,
|
||||
.irq_unmask = falcon_gpio_enable_irq,
|
||||
.irq_ack = falcon_gpio_ack_irq,
|
||||
.irq_mask_ack = falcon_gpio_mask_and_ack_irq,
|
||||
.irq_set_type = falcon_gpio_irq_type,
|
||||
};
|
||||
|
||||
static struct irqaction gpio_cascade = {
|
||||
.handler = no_action,
|
||||
.flags = IRQF_DISABLED,
|
||||
.name = "gpio_cascade",
|
||||
};
|
||||
|
||||
static int
|
||||
falcon_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct falcon_gpio_port *gpio_port;
|
||||
int ret, i;
|
||||
struct resource *gpiores, *padres;
|
||||
int irq;
|
||||
|
||||
if (pdev->id >= MAX_PORTS)
|
||||
return -ENODEV;
|
||||
|
||||
gpiores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
padres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!gpiores || !padres)
|
||||
return -ENODEV;
|
||||
|
||||
gpio_port = <q_gpio_port[pdev->id];
|
||||
gpio_port->gpio_chip.label = "falcon-gpio";
|
||||
gpio_port->gpio_chip.direction_input = falcon_gpio_direction_input;
|
||||
gpio_port->gpio_chip.direction_output = falcon_gpio_direction_output;
|
||||
gpio_port->gpio_chip.get = falcon_gpio_get;
|
||||
gpio_port->gpio_chip.set = falcon_gpio_set;
|
||||
gpio_port->gpio_chip.request = falcon_gpio_request;
|
||||
gpio_port->gpio_chip.free = falcon_gpio_free;
|
||||
gpio_port->gpio_chip.base = 100 * pdev->id;
|
||||
gpio_port->gpio_chip.ngpio = 32;
|
||||
gpio_port->gpio_chip.dev = &pdev->dev;
|
||||
|
||||
gpio_port->port = ltq_remap_resource(gpiores);
|
||||
gpio_port->pad = ltq_remap_resource(padres);
|
||||
|
||||
if (!gpio_port->port || !gpio_port->pad) {
|
||||
dev_err(&pdev->dev, "Could not map io ranges\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
gpio_port->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(gpio_port->clk)) {
|
||||
dev_err(&pdev->dev, "Could not get clock\n");
|
||||
ret = PTR_ERR(gpio_port->clk);;
|
||||
goto err;
|
||||
}
|
||||
clk_enable(gpio_port->clk);
|
||||
|
||||
if (irq > 0) {
|
||||
/* irq_chip support */
|
||||
gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq;
|
||||
gpio_port->irq_base = INT_NUM_EXTRA_START + (32 * pdev->id);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq_set_chip_and_handler_name(gpio_port->irq_base + i,
|
||||
&falcon_gpio_irq_chip, handle_simple_irq,
|
||||
"mux");
|
||||
irq_set_chip_data(gpio_port->irq_base + i, gpio_port);
|
||||
/* set to negative logic (falling edge, low level) */
|
||||
ltq_port_w32_mask(gpio_port, 0, 1 << i,
|
||||
LTQ_GPIO_EXINTCR0);
|
||||
}
|
||||
|
||||
gpio_port->chained_irq = irq;
|
||||
setup_irq(irq, &gpio_cascade);
|
||||
irq_set_handler_data(irq, gpio_port);
|
||||
irq_set_chained_handler(irq, falcon_gpio_irq_handler);
|
||||
}
|
||||
|
||||
ret = gpiochip_add(&gpio_port->gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip %d, %d\n",
|
||||
pdev->id, ret);
|
||||
goto err;
|
||||
}
|
||||
platform_set_drvdata(pdev, gpio_port);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
dev_err(&pdev->dev, "Error in gpio_probe %d, %d\n", pdev->id, ret);
|
||||
if (gpiores)
|
||||
release_resource(gpiores);
|
||||
if (padres)
|
||||
release_resource(padres);
|
||||
|
||||
if (gpio_port->port)
|
||||
iounmap(gpio_port->port);
|
||||
if (gpio_port->pad)
|
||||
iounmap(gpio_port->pad);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver falcon_gpio_driver = {
|
||||
.probe = falcon_gpio_probe,
|
||||
.driver = {
|
||||
.name = "falcon_gpio",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int __init
|
||||
falcon_gpio_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_info("FALC(tm) ON GPIO Driver, (C) 2011 Lantiq Deutschland Gmbh\n");
|
||||
ret = platform_driver_register(&falcon_gpio_driver);
|
||||
if (ret)
|
||||
pr_err("falcon_gpio: Error registering platform driver!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
postcore_initcall(falcon_gpio_init);
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_gpio.h>
|
||||
#include <linux/spi/eeprom.h>
|
||||
|
||||
#include "../machtypes.h"
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
static struct mtd_partition easy98000_nor_partitions[] = {
|
||||
{
|
||||
.name = "uboot",
|
||||
.offset = 0x0,
|
||||
.size = 0x40000,
|
||||
},
|
||||
{
|
||||
.name = "uboot_env",
|
||||
.offset = 0x40000,
|
||||
.size = 0x40000, /* 2 sectors for redundant env. */
|
||||
},
|
||||
{
|
||||
.name = "linux",
|
||||
.offset = 0x80000,
|
||||
.size = 0xF80000, /* map only 16 MiB */
|
||||
},
|
||||
};
|
||||
|
||||
struct physmap_flash_data easy98000_nor_flash_data = {
|
||||
.nr_parts = ARRAY_SIZE(easy98000_nor_partitions),
|
||||
.parts = easy98000_nor_partitions,
|
||||
};
|
||||
|
||||
static struct flash_platform_data easy98000_spi_flash_platform_data = {
|
||||
.name = "sflash",
|
||||
.parts = easy98000_nor_partitions,
|
||||
.nr_parts = ARRAY_SIZE(easy98000_nor_partitions)
|
||||
};
|
||||
|
||||
static struct spi_board_info easy98000_spi_flash_data __initdata = {
|
||||
.modalias = "m25p80",
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.max_speed_hz = 10 * 1000 * 1000,
|
||||
.mode = SPI_MODE_3,
|
||||
.platform_data = &easy98000_spi_flash_platform_data
|
||||
};
|
||||
|
||||
/* setup gpio based spi bus/device for access to the eeprom on the board */
|
||||
#define SPI_GPIO_MRST 102
|
||||
#define SPI_GPIO_MTSR 103
|
||||
#define SPI_GPIO_CLK 104
|
||||
#define SPI_GPIO_CS0 105
|
||||
#define SPI_GPIO_CS1 106
|
||||
#define SPI_GPIO_BUS_NUM 1
|
||||
|
||||
static struct spi_gpio_platform_data easy98000_spi_gpio_data = {
|
||||
.sck = SPI_GPIO_CLK,
|
||||
.mosi = SPI_GPIO_MTSR,
|
||||
.miso = SPI_GPIO_MRST,
|
||||
.num_chipselect = 2,
|
||||
};
|
||||
|
||||
static struct platform_device easy98000_spi_gpio_device = {
|
||||
.name = "spi_gpio",
|
||||
.id = SPI_GPIO_BUS_NUM,
|
||||
.dev.platform_data = &easy98000_spi_gpio_data,
|
||||
};
|
||||
|
||||
static struct spi_eeprom at25160n = {
|
||||
.byte_len = 16 * 1024 / 8,
|
||||
.name = "at25160n",
|
||||
.page_size = 32,
|
||||
.flags = EE_ADDR2,
|
||||
};
|
||||
|
||||
static struct spi_board_info easy98000_spi_gpio_devices __initdata = {
|
||||
.modalias = "at25",
|
||||
.bus_num = SPI_GPIO_BUS_NUM,
|
||||
.max_speed_hz = 1000 * 1000,
|
||||
.mode = SPI_MODE_3,
|
||||
.chip_select = 1,
|
||||
.controller_data = (void *) SPI_GPIO_CS1,
|
||||
.platform_data = &at25160n,
|
||||
};
|
||||
|
||||
static void __init
|
||||
easy98000_init_common(void)
|
||||
{
|
||||
spi_register_board_info(&easy98000_spi_gpio_devices, 1);
|
||||
platform_device_register(&easy98000_spi_gpio_device);
|
||||
falcon_register_i2c();
|
||||
}
|
||||
|
||||
static void __init
|
||||
easy98000_init(void)
|
||||
{
|
||||
easy98000_init_common();
|
||||
ltq_register_nor(&easy98000_nor_flash_data);
|
||||
}
|
||||
|
||||
static void __init
|
||||
easy98000sf_init(void)
|
||||
{
|
||||
easy98000_init_common();
|
||||
falcon_register_spi_flash(&easy98000_spi_flash_data);
|
||||
}
|
||||
|
||||
static void __init
|
||||
easy98000nand_init(void)
|
||||
{
|
||||
easy98000_init_common();
|
||||
falcon_register_nand();
|
||||
}
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY98000,
|
||||
"EASY98000",
|
||||
"EASY98000 Eval Board",
|
||||
easy98000_init);
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY98000SF,
|
||||
"EASY98000SF",
|
||||
"EASY98000 Eval Board (Serial Flash)",
|
||||
easy98000sf_init);
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY98000NAND,
|
||||
"EASY98000NAND",
|
||||
"EASY98000 Eval Board (NAND Flash)",
|
||||
easy98000nand_init);
|
||||
84
target/linux/lantiq/files/arch/mips/lantiq/falcon/prom.c
Normal file
84
target/linux/lantiq/files/arch/mips/lantiq/falcon/prom.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
#include "../prom.h"
|
||||
|
||||
#define SOC_FALCON "Falcon"
|
||||
#define SOC_FALCON_D "Falcon-D"
|
||||
#define SOC_FALCON_V "Falcon-V"
|
||||
#define SOC_FALCON_M "Falcon-M"
|
||||
|
||||
#define PART_SHIFT 12
|
||||
#define PART_MASK 0x0FFFF000
|
||||
#define REV_SHIFT 28
|
||||
#define REV_MASK 0xF0000000
|
||||
#define SREV_SHIFT 22
|
||||
#define SREV_MASK 0x03C00000
|
||||
#define TYPE_SHIFT 26
|
||||
#define TYPE_MASK 0x3C000000
|
||||
|
||||
/* this parameter allows us enable/disable asc1 via commandline */
|
||||
static int register_asc1;
|
||||
static int __init
|
||||
ltq_parse_asc1(char *p)
|
||||
{
|
||||
register_asc1 = 1;
|
||||
return 0;
|
||||
}
|
||||
__setup("use_asc1", ltq_parse_asc1);
|
||||
|
||||
void __init
|
||||
ltq_soc_setup(void)
|
||||
{
|
||||
ltq_register_asc(0);
|
||||
ltq_register_wdt();
|
||||
falcon_register_gpio();
|
||||
if (register_asc1)
|
||||
ltq_register_asc(1);
|
||||
}
|
||||
|
||||
void __init
|
||||
ltq_soc_detect(struct ltq_soc_info *i)
|
||||
{
|
||||
u32 type;
|
||||
i->partnum = (ltq_r32(LTQ_FALCON_CHIPID) & PART_MASK) >> PART_SHIFT;
|
||||
i->rev = (ltq_r32(LTQ_FALCON_CHIPID) & REV_MASK) >> REV_SHIFT;
|
||||
i->srev = ((ltq_r32(LTQ_FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT);
|
||||
sprintf(i->rev_type, "%c%d%d", (i->srev & 0x4) ? ('B') : ('A'),
|
||||
i->rev & 0x7, (i->srev & 0x3) + 1);
|
||||
|
||||
switch (i->partnum) {
|
||||
case SOC_ID_FALCON:
|
||||
type = (ltq_r32(LTQ_FALCON_CHIPTYPE) & TYPE_MASK) >> TYPE_SHIFT;
|
||||
switch (type) {
|
||||
case 0:
|
||||
i->name = SOC_FALCON_D;
|
||||
break;
|
||||
case 1:
|
||||
i->name = SOC_FALCON_V;
|
||||
break;
|
||||
case 2:
|
||||
i->name = SOC_FALCON_M;
|
||||
break;
|
||||
default:
|
||||
i->name = SOC_FALCON;
|
||||
break;
|
||||
}
|
||||
i->type = SOC_TYPE_FALCON;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
87
target/linux/lantiq/files/arch/mips/lantiq/falcon/reset.c
Normal file
87
target/linux/lantiq/files/arch/mips/lantiq/falcon/reset.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pm.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
/* CPU0 Reset Source Register */
|
||||
#define LTQ_SYS1_CPU0RS 0x0040
|
||||
/* reset cause mask */
|
||||
#define LTQ_CPU0RS_MASK 0x0003
|
||||
|
||||
int
|
||||
ltq_reset_cause(void)
|
||||
{
|
||||
return ltq_sys1_r32(LTQ_SYS1_CPU0RS) & LTQ_CPU0RS_MASK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ltq_reset_cause);
|
||||
|
||||
#define BOOT_REG_BASE (KSEG1 | 0x1F200000)
|
||||
#define BOOT_PW1_REG (BOOT_REG_BASE | 0x20)
|
||||
#define BOOT_PW2_REG (BOOT_REG_BASE | 0x24)
|
||||
#define BOOT_PW1 0x4C545100
|
||||
#define BOOT_PW2 0x0051544C
|
||||
|
||||
#define WDT_REG_BASE (KSEG1 | 0x1F8803F0)
|
||||
#define WDT_PW1 0x00BE0000
|
||||
#define WDT_PW2 0x00DC0000
|
||||
|
||||
static void
|
||||
ltq_machine_restart(char *command)
|
||||
{
|
||||
pr_notice("System restart\n");
|
||||
local_irq_disable();
|
||||
|
||||
/* reboot magic */
|
||||
ltq_w32(BOOT_PW1, (void *)BOOT_PW1_REG); /* 'LTQ\0' */
|
||||
ltq_w32(BOOT_PW2, (void *)BOOT_PW2_REG); /* '\0QTL' */
|
||||
ltq_w32(0, (void *)BOOT_REG_BASE); /* reset Bootreg RVEC */
|
||||
|
||||
/* watchdog magic */
|
||||
ltq_w32(WDT_PW1, (void *)WDT_REG_BASE);
|
||||
ltq_w32(WDT_PW2 |
|
||||
(0x3 << 26) | /* PWL */
|
||||
(0x2 << 24) | /* CLKDIV */
|
||||
(0x1 << 31) | /* enable */
|
||||
(1), /* reload */
|
||||
(void *)WDT_REG_BASE);
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static void
|
||||
ltq_machine_halt(void)
|
||||
{
|
||||
pr_notice("System halted.\n");
|
||||
local_irq_disable();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static void
|
||||
ltq_machine_power_off(void)
|
||||
{
|
||||
pr_notice("Please turn off the power now.\n");
|
||||
local_irq_disable();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static int __init
|
||||
mips_reboot_setup(void)
|
||||
{
|
||||
_machine_restart = ltq_machine_restart;
|
||||
_machine_halt = ltq_machine_halt;
|
||||
pm_power_off = ltq_machine_power_off;
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(mips_reboot_setup);
|
||||
211
target/linux/lantiq/files/arch/mips/lantiq/falcon/sysctrl.c
Normal file
211
target/linux/lantiq/files/arch/mips/lantiq/falcon/sysctrl.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <asm/delay.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "devices.h"
|
||||
#include "../clk.h"
|
||||
|
||||
/* infrastructure control register */
|
||||
#define SYS1_INFRAC 0x00bc
|
||||
/* Configuration fuses for drivers and pll */
|
||||
#define STATUS_CONFIG 0x0040
|
||||
|
||||
/* GPE frequency selection */
|
||||
#define GPPC_OFFSET 24
|
||||
#define GPEFREQ_MASK 0x00000C0
|
||||
#define GPEFREQ_OFFSET 10
|
||||
/* Clock status register */
|
||||
#define LTQ_SYSCTL_CLKS 0x0000
|
||||
/* Clock enable register */
|
||||
#define LTQ_SYSCTL_CLKEN 0x0004
|
||||
/* Clock clear register */
|
||||
#define LTQ_SYSCTL_CLKCLR 0x0008
|
||||
/* Activation Status Register */
|
||||
#define LTQ_SYSCTL_ACTS 0x0020
|
||||
/* Activation Register */
|
||||
#define LTQ_SYSCTL_ACT 0x0024
|
||||
/* Deactivation Register */
|
||||
#define LTQ_SYSCTL_DEACT 0x0028
|
||||
/* reboot Register */
|
||||
#define LTQ_SYSCTL_RBT 0x002c
|
||||
/* CPU0 Clock Control Register */
|
||||
#define LTQ_SYS1_CPU0CC 0x0040
|
||||
/* clock divider bit */
|
||||
#define LTQ_CPU0CC_CPUDIV 0x0001
|
||||
|
||||
static struct resource ltq_sysctl_res[] = {
|
||||
MEM_RES("sys1", LTQ_SYS1_BASE_ADDR, LTQ_SYS1_SIZE),
|
||||
MEM_RES("syseth", LTQ_SYS_ETH_BASE_ADDR, LTQ_SYS_ETH_SIZE),
|
||||
MEM_RES("sysgpe", LTQ_SYS_GPE_BASE_ADDR, LTQ_SYS_GPE_SIZE),
|
||||
};
|
||||
|
||||
static struct resource ltq_status_res =
|
||||
MEM_RES("status", LTQ_STATUS_BASE_ADDR, LTQ_STATUS_SIZE);
|
||||
static struct resource ltq_ebu_res =
|
||||
MEM_RES("ebu", LTQ_EBU_BASE_ADDR, LTQ_EBU_SIZE);
|
||||
|
||||
static void __iomem *ltq_sysctl[3];
|
||||
static void __iomem *ltq_status_membase;
|
||||
void __iomem *ltq_sys1_membase;
|
||||
void __iomem *ltq_ebu_membase;
|
||||
|
||||
#define ltq_reg_w32(m, x, y) ltq_w32((x), ltq_sysctl[m] + (y))
|
||||
#define ltq_reg_r32(m, x) ltq_r32(ltq_sysctl[m] + (x))
|
||||
#define ltq_reg_w32_mask(m, clear, set, reg) \
|
||||
ltq_reg_w32(m, (ltq_reg_r32(m, reg) & ~(clear)) | (set), reg)
|
||||
|
||||
#define ltq_status_w32(x, y) ltq_w32((x), ltq_status_membase + (y))
|
||||
#define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x))
|
||||
|
||||
static inline void
|
||||
ltq_sysctl_wait(struct clk *clk,
|
||||
unsigned int test, unsigned int reg)
|
||||
{
|
||||
int err = 1000000;
|
||||
|
||||
do {} while (--err && ((ltq_reg_r32(clk->module, reg)
|
||||
& clk->bits) != test));
|
||||
if (!err)
|
||||
pr_err("module de/activation failed %d %08X %08X %08X\n",
|
||||
clk->module, clk->bits, test,
|
||||
ltq_reg_r32(clk->module, reg) & clk->bits);
|
||||
}
|
||||
|
||||
static int
|
||||
ltq_sysctl_activate(struct clk *clk)
|
||||
{
|
||||
ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN);
|
||||
ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_ACT);
|
||||
ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ltq_sysctl_deactivate(struct clk *clk)
|
||||
{
|
||||
ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR);
|
||||
ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_DEACT);
|
||||
ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_ACTS);
|
||||
}
|
||||
|
||||
static int
|
||||
ltq_sysctl_clken(struct clk *clk)
|
||||
{
|
||||
ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN);
|
||||
ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_CLKS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ltq_sysctl_clkdis(struct clk *clk)
|
||||
{
|
||||
ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR);
|
||||
ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_CLKS);
|
||||
}
|
||||
|
||||
static void
|
||||
ltq_sysctl_reboot(struct clk *clk)
|
||||
{
|
||||
unsigned int act;
|
||||
unsigned int bits;
|
||||
|
||||
act = ltq_reg_r32(clk->module, LTQ_SYSCTL_ACT);
|
||||
bits = ~act & clk->bits;
|
||||
if (bits != 0) {
|
||||
ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_CLKEN);
|
||||
ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_ACT);
|
||||
ltq_sysctl_wait(clk, bits, LTQ_SYSCTL_ACTS);
|
||||
}
|
||||
ltq_reg_w32(clk->module, act & clk->bits, LTQ_SYSCTL_RBT);
|
||||
ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS);
|
||||
}
|
||||
|
||||
/* enable the ONU core */
|
||||
static void
|
||||
ltq_gpe_enable(void)
|
||||
{
|
||||
unsigned int freq;
|
||||
unsigned int status;
|
||||
|
||||
/* if if the clock is already enabled */
|
||||
status = ltq_reg_r32(SYSCTL_SYS1, SYS1_INFRAC);
|
||||
if (status & (1 << (GPPC_OFFSET + 1)))
|
||||
return;
|
||||
|
||||
if (ltq_status_r32(STATUS_CONFIG) == 0)
|
||||
freq = 1; /* use 625MHz on unfused chip */
|
||||
else
|
||||
freq = (ltq_status_r32(STATUS_CONFIG) &
|
||||
GPEFREQ_MASK) >>
|
||||
GPEFREQ_OFFSET;
|
||||
|
||||
/* apply new frequency */
|
||||
ltq_reg_w32_mask(SYSCTL_SYS1, 7 << (GPPC_OFFSET + 1),
|
||||
freq << (GPPC_OFFSET + 2) , SYS1_INFRAC);
|
||||
udelay(1);
|
||||
|
||||
/* enable new frequency */
|
||||
ltq_reg_w32_mask(SYSCTL_SYS1, 0, 1 << (GPPC_OFFSET + 1), SYS1_INFRAC);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
clkdev_add_sys(const char *dev, unsigned int module,
|
||||
unsigned int bits)
|
||||
{
|
||||
struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
|
||||
|
||||
clk->cl.dev_id = dev;
|
||||
clk->cl.con_id = NULL;
|
||||
clk->cl.clk = clk;
|
||||
clk->module = module;
|
||||
clk->bits = bits;
|
||||
clk->activate = ltq_sysctl_activate;
|
||||
clk->deactivate = ltq_sysctl_deactivate;
|
||||
clk->enable = ltq_sysctl_clken;
|
||||
clk->disable = ltq_sysctl_clkdis;
|
||||
clk->reboot = ltq_sysctl_reboot;
|
||||
clkdev_add(&clk->cl);
|
||||
}
|
||||
|
||||
void __init
|
||||
ltq_soc_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
ltq_sysctl[i] = ltq_remap_resource(<q_sysctl_res[i]);
|
||||
|
||||
ltq_sys1_membase = ltq_sysctl[0];
|
||||
ltq_status_membase = ltq_remap_resource(<q_status_res);
|
||||
ltq_ebu_membase = ltq_remap_resource(<q_ebu_res);
|
||||
|
||||
ltq_gpe_enable();
|
||||
|
||||
/* get our 3 static rates for cpu, fpi and io clocks */
|
||||
if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV)
|
||||
clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M);
|
||||
else
|
||||
clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M);
|
||||
|
||||
/* add our clock domains */
|
||||
clkdev_add_sys("falcon_gpio.0", SYSCTL_SYSETH, ACTS_PADCTRL0 | ACTS_P0);
|
||||
clkdev_add_sys("falcon_gpio.1", SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1);
|
||||
clkdev_add_sys("falcon_gpio.2", SYSCTL_SYSETH, ACTS_PADCTRL2 | ACTS_P2);
|
||||
clkdev_add_sys("falcon_gpio.3", SYSCTL_SYS1, ACTS_PADCTRL3 | ACTS_P3);
|
||||
clkdev_add_sys("falcon_gpio.4", SYSCTL_SYS1, ACTS_PADCTRL4 | ACTS_P4);
|
||||
clkdev_add_sys("ltq_asc.1", SYSCTL_SYS1, ACTS_ASC1_ACT);
|
||||
clkdev_add_sys("i2c-falcon.0", SYSCTL_SYS1, ACTS_I2C_ACT);
|
||||
}
|
||||
16
target/linux/lantiq/files/arch/mips/lantiq/svip/Kconfig
Normal file
16
target/linux/lantiq/files/arch/mips/lantiq/svip/Kconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
if SOC_SVIP
|
||||
|
||||
menu "Mips Machine"
|
||||
|
||||
config LANTIQ_MACH_EASY33016
|
||||
bool "Easy33016"
|
||||
default y
|
||||
|
||||
config LANTIQ_MACH_EASY336
|
||||
select SYS_SUPPORTS_LITTLE_ENDIAN
|
||||
bool "Easy336"
|
||||
default y
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
3
target/linux/lantiq/files/arch/mips/lantiq/svip/Makefile
Normal file
3
target/linux/lantiq/files/arch/mips/lantiq/svip/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-y := devices.o prom.o reset.o clk-svip.o gpio.o dma.o switchip_setup.o pms.o mux.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY33016) += mach-easy33016.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY336) += mach-easy336.o
|
||||
100
target/linux/lantiq/files/arch/mips/lantiq/svip/clk-svip.c
Normal file
100
target/linux/lantiq/files/arch/mips/lantiq/svip/clk-svip.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <base_reg.h>
|
||||
#include <sys0_reg.h>
|
||||
#include <sys1_reg.h>
|
||||
#include <status_reg.h>
|
||||
|
||||
static struct svip_reg_status *const status =
|
||||
(struct svip_reg_status *)LTQ_STATUS_BASE;
|
||||
static struct svip_reg_sys0 *const sys0 = (struct svip_reg_sys0 *)LTQ_SYS0_BASE;
|
||||
static struct svip_reg_sys1 *const sys1 = (struct svip_reg_sys1 *)LTQ_SYS1_BASE;
|
||||
|
||||
unsigned int ltq_svip_io_region_clock(void)
|
||||
{
|
||||
return 200000000; /* 200 MHz */
|
||||
}
|
||||
EXPORT_SYMBOL(ltq_svip_io_region_clock);
|
||||
|
||||
unsigned int ltq_svip_cpu_hz(void)
|
||||
{
|
||||
/* Magic BootROM speed location... */
|
||||
if ((*(u32 *)0x9fc07ff0) == 1)
|
||||
return *(u32 *)0x9fc07ff4;
|
||||
|
||||
if (STATUS_CONFIG_CLK_MODE_GET(status_r32(config)) == 1) {
|
||||
/* xT16 */
|
||||
return 393216000;
|
||||
} else {
|
||||
switch (SYS0_PLL1CR_PLLDIV_GET(sys0_r32(pll1cr))) {
|
||||
case 3:
|
||||
return 475000000;
|
||||
case 2:
|
||||
return 450000000;
|
||||
case 1:
|
||||
return 425000000;
|
||||
default:
|
||||
return 400000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ltq_svip_cpu_hz);
|
||||
|
||||
unsigned int ltq_svip_fpi_hz(void)
|
||||
{
|
||||
u32 fbs0_div[2] = {4, 8};
|
||||
u32 div;
|
||||
|
||||
div = SYS1_FPICR_FPIDIV_GET(sys1_r32(fpicr));
|
||||
return ltq_svip_cpu_hz()/fbs0_div[div];
|
||||
}
|
||||
EXPORT_SYMBOL(ltq_svip_fpi_hz);
|
||||
|
||||
unsigned int ltq_get_ppl_hz(void)
|
||||
{
|
||||
/* Magic BootROM speed location... */
|
||||
if ((*(u32 *)0x9fc07ff0) == 1)
|
||||
return *(u32 *)0x9fc07ff4;
|
||||
|
||||
if (STATUS_CONFIG_CLK_MODE_GET(status_r32(config)) == 1) {
|
||||
/* xT16 */
|
||||
return 393216000;
|
||||
} else {
|
||||
switch (SYS0_PLL1CR_PLLDIV_GET(sys0_r32(pll1cr))) {
|
||||
case 3:
|
||||
return 475000000;
|
||||
case 2:
|
||||
return 450000000;
|
||||
case 1:
|
||||
return 425000000;
|
||||
default:
|
||||
return 400000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ltq_get_fbs0_hz(void)
|
||||
{
|
||||
u32 fbs0_div[2] = {4, 8};
|
||||
u32 div;
|
||||
|
||||
div = SYS1_FPICR_FPIDIV_GET(sys1_r32(fpicr));
|
||||
return ltq_get_ppl_hz()/fbs0_div[div];
|
||||
}
|
||||
EXPORT_SYMBOL(ltq_get_fbs0_hz);
|
||||
385
target/linux/lantiq/files/arch/mips/lantiq/svip/devices.c
Normal file
385
target/linux/lantiq/files/arch/mips/lantiq/svip/devices.c
Normal file
@@ -0,0 +1,385 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <lantiq.h>
|
||||
|
||||
#include <base_reg.h>
|
||||
#include <sys1_reg.h>
|
||||
#include <sys2_reg.h>
|
||||
#include <ebu_reg.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <svip_mux.h>
|
||||
#include <svip_pms.h>
|
||||
|
||||
/* ASC */
|
||||
void __init svip_register_asc(int port)
|
||||
{
|
||||
switch (port) {
|
||||
case 0:
|
||||
ltq_register_asc(0);
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_ASC0);
|
||||
break;
|
||||
case 1:
|
||||
ltq_register_asc(1);
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_ASC1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
/* Ethernet */
|
||||
static unsigned char svip_ethaddr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
static struct platform_device ltq_mii = {
|
||||
.name = "ifxmips_mii0",
|
||||
.dev = {
|
||||
.platform_data = svip_ethaddr,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init svip_set_ethaddr(char *str)
|
||||
{
|
||||
sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
&svip_ethaddr[0], &svip_ethaddr[1], &svip_ethaddr[2],
|
||||
&svip_ethaddr[3], &svip_ethaddr[4], &svip_ethaddr[5]);
|
||||
return 0;
|
||||
}
|
||||
__setup("ethaddr=", svip_set_ethaddr);
|
||||
|
||||
void __init svip_register_eth(void)
|
||||
{
|
||||
if (!is_valid_ether_addr(svip_ethaddr))
|
||||
random_ether_addr(svip_ethaddr);
|
||||
|
||||
platform_device_register(<q_mii);
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_ETHSW);
|
||||
}
|
||||
|
||||
/* Virtual Ethernet */
|
||||
static struct platform_device ltq_ve = {
|
||||
.name = "ifxmips_svip_ve",
|
||||
};
|
||||
|
||||
void __init svip_register_virtual_eth(void)
|
||||
{
|
||||
platform_device_register(<q_ve);
|
||||
}
|
||||
|
||||
/* SPI */
|
||||
static void __init ltq_register_ssc(int bus_num, unsigned long base, int irq_rx,
|
||||
int irq_tx, int irq_err, int irq_frm)
|
||||
{
|
||||
struct resource res[] = {
|
||||
{
|
||||
.name = "regs",
|
||||
.start = base,
|
||||
.end = base + 0x20 - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
}, {
|
||||
.name = "rx",
|
||||
.start = irq_rx,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
.name = "tx",
|
||||
.start = irq_tx,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
.name = "err",
|
||||
.start = irq_err,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}, {
|
||||
.name = "frm",
|
||||
.start = irq_frm,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
platform_device_register_simple("ifx_ssc", bus_num, res,
|
||||
ARRAY_SIZE(res));
|
||||
}
|
||||
|
||||
static struct spi_board_info bdinfo[] __initdata = {
|
||||
{
|
||||
.modalias = "xt16",
|
||||
.mode = SPI_MODE_3,
|
||||
.irq = INT_NUM_IM5_IRL0 + 28,
|
||||
.max_speed_hz = 1000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 1,
|
||||
},
|
||||
{
|
||||
.modalias = "xt16",
|
||||
.mode = SPI_MODE_3,
|
||||
.irq = INT_NUM_IM5_IRL0 + 19,
|
||||
.max_speed_hz = 1000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 2,
|
||||
},
|
||||
{
|
||||
.modalias = "loop",
|
||||
.mode = SPI_MODE_0 | SPI_LOOP,
|
||||
.irq = -1,
|
||||
.max_speed_hz = 10000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 3,
|
||||
},
|
||||
};
|
||||
|
||||
void __init svip_register_spi(void)
|
||||
{
|
||||
|
||||
ltq_register_ssc(0, LTQ_SSC0_BASE, INT_NUM_IM1_IRL0 + 6,
|
||||
INT_NUM_IM1_IRL0 + 7, INT_NUM_IM1_IRL0 + 8,
|
||||
INT_NUM_IM1_IRL0 + 9);
|
||||
|
||||
ltq_register_ssc(1, LTQ_SSC1_BASE, INT_NUM_IM1_IRL0 + 10,
|
||||
INT_NUM_IM1_IRL0 + 11, INT_NUM_IM1_IRL0 + 12,
|
||||
INT_NUM_IM1_IRL0 + 13);
|
||||
|
||||
spi_register_board_info(bdinfo, ARRAY_SIZE(bdinfo));
|
||||
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_SSC0 | SYS1_CLKENR_SSC1);
|
||||
}
|
||||
|
||||
void __init svip_register_spi_flash(struct spi_board_info *bdinfo)
|
||||
{
|
||||
spi_register_board_info(bdinfo, 1);
|
||||
}
|
||||
|
||||
/* GPIO */
|
||||
static struct platform_device ltq_gpio = {
|
||||
.name = "ifxmips_gpio",
|
||||
};
|
||||
|
||||
static struct platform_device ltq_gpiodev = {
|
||||
.name = "GPIODEV",
|
||||
};
|
||||
|
||||
void __init svip_register_gpio(void)
|
||||
{
|
||||
platform_device_register(<q_gpio);
|
||||
platform_device_register(<q_gpiodev);
|
||||
}
|
||||
|
||||
/* MUX */
|
||||
static struct ltq_mux_settings ltq_mux_settings;
|
||||
|
||||
static struct platform_device ltq_mux = {
|
||||
.name = "ltq_mux",
|
||||
.dev = {
|
||||
.platform_data = <q_mux_settings,
|
||||
}
|
||||
};
|
||||
|
||||
void __init svip_register_mux(const struct ltq_mux_pin mux_p0[LTQ_MUX_P0_PINS],
|
||||
const struct ltq_mux_pin mux_p1[LTQ_MUX_P1_PINS],
|
||||
const struct ltq_mux_pin mux_p2[LTQ_MUX_P2_PINS],
|
||||
const struct ltq_mux_pin mux_p3[LTQ_MUX_P3_PINS],
|
||||
const struct ltq_mux_pin mux_p4[LTQ_MUX_P4_PINS])
|
||||
{
|
||||
ltq_mux_settings.mux_p0 = mux_p0;
|
||||
ltq_mux_settings.mux_p1 = mux_p1;
|
||||
ltq_mux_settings.mux_p2 = mux_p2;
|
||||
ltq_mux_settings.mux_p3 = mux_p3;
|
||||
ltq_mux_settings.mux_p4 = mux_p4;
|
||||
|
||||
if (mux_p0)
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_PORT0);
|
||||
|
||||
if (mux_p1)
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_PORT1);
|
||||
|
||||
if (mux_p2)
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_PORT2);
|
||||
|
||||
if (mux_p3)
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_PORT3);
|
||||
|
||||
if (mux_p4)
|
||||
svip_sys2_clk_enable(SYS2_CLKENR_PORT4);
|
||||
|
||||
platform_device_register(<q_mux);
|
||||
}
|
||||
|
||||
/* NAND */
|
||||
#define NAND_ADDR_REGION_BASE (LTQ_EBU_SEG1_BASE)
|
||||
#define NAND_CLE_BIT (1 << 3)
|
||||
#define NAND_ALE_BIT (1 << 2)
|
||||
|
||||
static struct svip_reg_ebu *const ebu = (struct svip_reg_ebu *)LTQ_EBU_BASE;
|
||||
|
||||
static int svip_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
ebu_w32(LTQ_EBU_ADDR_SEL_0_BASE_VAL(CPHYSADDR(NAND_ADDR_REGION_BASE)
|
||||
>> 12)
|
||||
| LTQ_EBU_ADDR_SEL_0_MASK_VAL(15)
|
||||
| LTQ_EBU_ADDR_SEL_0_MRME_VAL(0)
|
||||
| LTQ_EBU_ADDR_SEL_0_REGEN_VAL(1),
|
||||
addr_sel_0);
|
||||
|
||||
ebu_w32(LTQ_EBU_CON_0_WRDIS_VAL(0)
|
||||
| LTQ_EBU_CON_0_ADSWP_VAL(1)
|
||||
| LTQ_EBU_CON_0_AGEN_VAL(0x00)
|
||||
| LTQ_EBU_CON_0_SETUP_VAL(1)
|
||||
| LTQ_EBU_CON_0_WAIT_VAL(0x00)
|
||||
| LTQ_EBU_CON_0_WINV_VAL(0)
|
||||
| LTQ_EBU_CON_0_PW_VAL(0x00)
|
||||
| LTQ_EBU_CON_0_ALEC_VAL(0)
|
||||
| LTQ_EBU_CON_0_BCGEN_VAL(0x01)
|
||||
| LTQ_EBU_CON_0_WAITWRC_VAL(1)
|
||||
| LTQ_EBU_CON_0_WAITRDC_VAL(1)
|
||||
| LTQ_EBU_CON_0_HOLDC_VAL(1)
|
||||
| LTQ_EBU_CON_0_RECOVC_VAL(0)
|
||||
| LTQ_EBU_CON_0_CMULT_VAL(0x01),
|
||||
con_0);
|
||||
|
||||
/*
|
||||
* ECC disabled
|
||||
* CLE, ALE and CS are pulse, all other signal are latches based
|
||||
* CLE and ALE are active high, PRE, WP, SE and CS/CE are active low
|
||||
* OUT_CS_S is disabled
|
||||
* NAND mode is disabled
|
||||
*/
|
||||
ebu_w32(LTQ_EBU_NAND_CON_ECC_ON_VAL(0)
|
||||
| LTQ_EBU_NAND_CON_LAT_EN_VAL(0x38)
|
||||
| LTQ_EBU_NAND_CON_OUT_CS_S_VAL(0)
|
||||
| LTQ_EBU_NAND_CON_IN_CS_S_VAL(0)
|
||||
| LTQ_EBU_NAND_CON_PRE_P_VAL(1)
|
||||
| LTQ_EBU_NAND_CON_WP_P_VAL(1)
|
||||
| LTQ_EBU_NAND_CON_SE_P_VAL(1)
|
||||
| LTQ_EBU_NAND_CON_CS_P_VAL(1)
|
||||
| LTQ_EBU_NAND_CON_CLE_P_VAL(0)
|
||||
| LTQ_EBU_NAND_CON_ALE_P_VAL(0)
|
||||
| LTQ_EBU_NAND_CON_CSMUX_E_VAL(0)
|
||||
| LTQ_EBU_NAND_CON_NANDMODE_VAL(0),
|
||||
nand_con);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void svip_nand_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
unsigned long adr;
|
||||
/* Coming here means to change either the enable state or
|
||||
* the address for controlling ALE or CLE */
|
||||
|
||||
/* NAND_NCE: Select the chip by setting nCE to low.
|
||||
* This is done in CON register */
|
||||
if (ctrl & NAND_NCE)
|
||||
ebu_w32_mask(0, LTQ_EBU_NAND_CON_NANDMODE_VAL(1),
|
||||
nand_con);
|
||||
else
|
||||
ebu_w32_mask(LTQ_EBU_NAND_CON_NANDMODE_VAL(1),
|
||||
0, nand_con);
|
||||
|
||||
/* The addressing of CLE or ALE is done via different addresses.
|
||||
We are now changing the address depending on the given action
|
||||
SVIPs NAND_CLE_BIT = (1 << 3), NAND_CLE = 0x02
|
||||
NAND_ALE_BIT = (1 << 2) = NAND_ALE (0x04) */
|
||||
adr = (unsigned long)this->IO_ADDR_W;
|
||||
adr &= ~(NAND_CLE_BIT | NAND_ALE_BIT);
|
||||
adr |= (ctrl & NAND_CLE) << 2 | (ctrl & NAND_ALE);
|
||||
this->IO_ADDR_W = (void __iomem *)adr;
|
||||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int svip_nand_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return (ebu_r32(nand_wait) & 0x01) == 0x01;
|
||||
}
|
||||
|
||||
static inline void svip_nand_wait(void)
|
||||
{
|
||||
static const int nops = 150;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nops; i++)
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
static void svip_nand_write_buf(struct mtd_info *mtd,
|
||||
const u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
writeb(buf[i], this->IO_ADDR_W);
|
||||
svip_nand_wait();
|
||||
}
|
||||
}
|
||||
|
||||
static void svip_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = readb(this->IO_ADDR_R);
|
||||
svip_nand_wait();
|
||||
}
|
||||
}
|
||||
|
||||
static const char *part_probes[] = { "cmdlinepart", NULL };
|
||||
|
||||
static struct platform_nand_data svip_flash_nand_data = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.part_probe_types = part_probes,
|
||||
},
|
||||
.ctrl = {
|
||||
.probe = svip_nand_probe,
|
||||
.cmd_ctrl = svip_nand_hwcontrol,
|
||||
.dev_ready = svip_nand_ready,
|
||||
.write_buf = svip_nand_write_buf,
|
||||
.read_buf = svip_nand_read_buf,
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource svip_nand_resources[] = {
|
||||
MEM_RES("nand", LTQ_FLASH_START, LTQ_FLASH_MAX),
|
||||
};
|
||||
|
||||
static struct platform_device svip_flash_nand = {
|
||||
.name = "gen_nand",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(svip_nand_resources),
|
||||
.resource = svip_nand_resources,
|
||||
.dev = {
|
||||
.platform_data = &svip_flash_nand_data,
|
||||
},
|
||||
};
|
||||
|
||||
void __init svip_register_nand(void)
|
||||
{
|
||||
platform_device_register(&svip_flash_nand);
|
||||
}
|
||||
23
target/linux/lantiq/files/arch/mips/lantiq/svip/devices.h
Normal file
23
target/linux/lantiq/files/arch/mips/lantiq/svip/devices.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef _SVIP_DEVICES_H__
|
||||
#define _SVIP_DEVICES_H__
|
||||
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <svip_mux.h>
|
||||
#include "../devices.h"
|
||||
|
||||
extern void __init svip_register_asc(int port);
|
||||
extern void __init svip_register_eth(void);
|
||||
extern void __init svip_register_virtual_eth(void);
|
||||
extern void __init svip_register_spi(void);
|
||||
extern void __init svip_register_spi_flash(struct spi_board_info *bdinfo);
|
||||
extern void __init svip_register_gpio(void);
|
||||
extern void __init svip_register_mux(const struct ltq_mux_pin mux_p0[LTQ_MUX_P0_PINS],
|
||||
const struct ltq_mux_pin mux_p1[LTQ_MUX_P1_PINS],
|
||||
const struct ltq_mux_pin mux_p2[LTQ_MUX_P2_PINS],
|
||||
const struct ltq_mux_pin mux_p3[LTQ_MUX_P3_PINS],
|
||||
const struct ltq_mux_pin mux_p4[LTQ_MUX_P4_PINS]);
|
||||
extern void __init svip_register_nand(void);
|
||||
|
||||
#endif
|
||||
1206
target/linux/lantiq/files/arch/mips/lantiq/svip/dma.c
Normal file
1206
target/linux/lantiq/files/arch/mips/lantiq/svip/dma.c
Normal file
File diff suppressed because it is too large
Load Diff
553
target/linux/lantiq/files/arch/mips/lantiq/svip/gpio.c
Normal file
553
target/linux/lantiq/files/arch/mips/lantiq/svip/gpio.c
Normal file
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <svip_mux.h>
|
||||
#include <base_reg.h>
|
||||
#include <port_reg.h>
|
||||
|
||||
#define DRV_NAME "ifxmips_gpio"
|
||||
|
||||
int gpio_to_irq(unsigned int gpio)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_to_irq);
|
||||
|
||||
int irq_to_gpio(unsigned int gpio)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(irq_to_gpio);
|
||||
|
||||
struct ltq_port_base {
|
||||
struct svip_reg_port *base;
|
||||
u32 pins;
|
||||
};
|
||||
|
||||
/* Base addresses for ports */
|
||||
static const struct ltq_port_base ltq_port_base[] = {
|
||||
{ (struct svip_reg_port *)LTQ_PORT_P0_BASE, 20 },
|
||||
{ (struct svip_reg_port *)LTQ_PORT_P1_BASE, 20 },
|
||||
{ (struct svip_reg_port *)LTQ_PORT_P2_BASE, 19 },
|
||||
{ (struct svip_reg_port *)LTQ_PORT_P3_BASE, 20 },
|
||||
{ (struct svip_reg_port *)LTQ_PORT_P4_BASE, 24 }
|
||||
};
|
||||
|
||||
#define MAX_PORTS ARRAY_SIZE(ltq_port_base)
|
||||
#define PINS_PER_PORT(port) (ltq_port_base[port].pins)
|
||||
|
||||
static inline
|
||||
void ltq_port_set_exintcr0(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->exintcr0) | (1 << pin),
|
||||
ltq_port_base[port].base->exintcr0);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_exintcr0(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->exintcr0) & ~(1 << pin),
|
||||
ltq_port_base[port].base->exintcr0);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_exintcr1(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->exintcr1) | (1 << pin),
|
||||
ltq_port_base[port].base->exintcr1);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_exintcr1(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->exintcr1) & ~(1 << pin),
|
||||
ltq_port_base[port].base->exintcr1);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_irncfg(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->irncfg) | (1 << pin),
|
||||
ltq_port_base[port].base->irncfg);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_irncfg(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->irncfg) & ~(1 << pin),
|
||||
ltq_port_base[port].base->irncfg);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_irnen(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(1 << pin, ltq_port_base[port].base->irnenset);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_irnen(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(1 << pin, ltq_port_base[port].base->irnenclr);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_dir_out(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->dir) | (1 << pin),
|
||||
ltq_port_base[port].base->dir);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_dir_in(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->dir) & ~(1 << pin),
|
||||
ltq_port_base[port].base->dir);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_output(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->out) | (1 << pin),
|
||||
ltq_port_base[port].base->out);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_output(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->out) & ~(1 << pin),
|
||||
ltq_port_base[port].base->out);
|
||||
}
|
||||
|
||||
static inline
|
||||
int ltq_port_get_input(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return -EINVAL;
|
||||
|
||||
return (port_r32(ltq_port_base[port].base->in) & (1 << pin)) == 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_puen(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->puen) | (1 << pin),
|
||||
ltq_port_base[port].base->puen);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_puen(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->puen) & ~(1 << pin),
|
||||
ltq_port_base[port].base->puen);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_altsel0(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->altsel0) | (1 << pin),
|
||||
ltq_port_base[port].base->altsel0);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_altsel0(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->altsel0) & ~(1 << pin),
|
||||
ltq_port_base[port].base->altsel0);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_set_altsel1(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->altsel1) | (1 << pin),
|
||||
ltq_port_base[port].base->altsel1);
|
||||
}
|
||||
|
||||
static inline
|
||||
void ltq_port_clear_altsel1(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return;
|
||||
|
||||
port_w32(port_r32(ltq_port_base[port].base->altsel1) & ~(1 << pin),
|
||||
ltq_port_base[port].base->altsel1);
|
||||
}
|
||||
|
||||
void ltq_gpio_configure(int port, int pin, bool dirin, bool puen,
|
||||
bool altsel0, bool altsel1)
|
||||
{
|
||||
if (dirin)
|
||||
ltq_port_set_dir_in(port, pin);
|
||||
else
|
||||
ltq_port_set_dir_out(port, pin);
|
||||
|
||||
if (puen)
|
||||
ltq_port_set_puen(port, pin);
|
||||
else
|
||||
ltq_port_clear_puen(port, pin);
|
||||
|
||||
if (altsel0)
|
||||
ltq_port_set_altsel0(port, pin);
|
||||
else
|
||||
ltq_port_clear_altsel0(port, pin);
|
||||
|
||||
if (altsel1)
|
||||
ltq_port_set_altsel1(port, pin);
|
||||
else
|
||||
ltq_port_clear_altsel1(port, pin);
|
||||
}
|
||||
|
||||
int ltq_port_get_dir(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return -EINVAL;
|
||||
|
||||
return (port_r32(ltq_port_base[port].base->dir) & (1 << pin)) != 0;
|
||||
}
|
||||
|
||||
int ltq_port_get_puden(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return -EINVAL;
|
||||
|
||||
return (port_r32(ltq_port_base[port].base->puen) & (1 << pin)) != 0;
|
||||
}
|
||||
|
||||
int ltq_port_get_altsel0(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return -EINVAL;
|
||||
|
||||
return (port_r32(ltq_port_base[port].base->altsel0) & (1 << pin)) != 0;
|
||||
}
|
||||
|
||||
int ltq_port_get_altsel1(unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port >= MAX_PORTS || pin >= PINS_PER_PORT(port))
|
||||
return -EINVAL;
|
||||
|
||||
return (port_r32(ltq_port_base[port].base->altsel1) & (1 << pin)) != 0;
|
||||
}
|
||||
|
||||
struct ltq_gpio_port {
|
||||
struct gpio_chip gpio_chip;
|
||||
unsigned int irq_base;
|
||||
unsigned int chained_irq;
|
||||
};
|
||||
|
||||
static struct ltq_gpio_port ltq_gpio_port[MAX_PORTS];
|
||||
|
||||
static int gpio_exported;
|
||||
static int __init gpio_export_setup(char *str)
|
||||
{
|
||||
get_option(&str, &gpio_exported);
|
||||
return 1;
|
||||
}
|
||||
__setup("gpio_exported=", gpio_export_setup);
|
||||
|
||||
static inline unsigned int offset2port(unsigned int offset)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int prev = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ltq_port_base); i++) {
|
||||
if (offset >= prev &&
|
||||
offset < prev + ltq_port_base[i].pins)
|
||||
return i;
|
||||
|
||||
prev = ltq_port_base[i].pins;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int offset2pin(unsigned int offset)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int prev = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ltq_port_base); i++) {
|
||||
if (offset >= prev &&
|
||||
offset < prev + ltq_port_base[i].pins)
|
||||
return offset - prev;
|
||||
|
||||
prev = ltq_port_base[i].pins;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
ltq_port_set_dir_in(offset2port(offset), offset2pin(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltq_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
ltq_port_set_dir_out(offset2port(offset), offset2pin(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return ltq_port_get_input(offset2port(offset), offset2pin(offset));
|
||||
}
|
||||
|
||||
static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
if (value)
|
||||
ltq_port_set_output(offset2port(offset), offset2pin(offset));
|
||||
else
|
||||
ltq_port_clear_output(offset2port(offset), offset2pin(offset));
|
||||
}
|
||||
|
||||
static int svip_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltq_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
}
|
||||
|
||||
static int ltq_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ltq_gpio_port *gpio_port;
|
||||
|
||||
if (pdev->id >= MAX_PORTS)
|
||||
return -ENODEV;
|
||||
|
||||
gpio_port = <q_gpio_port[pdev->id];
|
||||
gpio_port->gpio_chip.label = "ltq-gpio";
|
||||
|
||||
gpio_port->gpio_chip.direction_input = ltq_gpio_direction_input;
|
||||
gpio_port->gpio_chip.direction_output = ltq_gpio_direction_output;
|
||||
gpio_port->gpio_chip.get = ltq_gpio_get;
|
||||
gpio_port->gpio_chip.set = ltq_gpio_set;
|
||||
gpio_port->gpio_chip.request = svip_gpio_request;
|
||||
gpio_port->gpio_chip.free = ltq_gpio_free;
|
||||
gpio_port->gpio_chip.base = 100 * pdev->id;
|
||||
gpio_port->gpio_chip.ngpio = 32;
|
||||
gpio_port->gpio_chip.dev = &pdev->dev;
|
||||
gpio_port->gpio_chip.exported = gpio_exported;
|
||||
|
||||
ret = gpiochip_add(&gpio_port->gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip %d, %d\n",
|
||||
pdev->id, ret);
|
||||
goto err;
|
||||
}
|
||||
platform_set_drvdata(pdev, gpio_port);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltq_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ltq_gpio_port *gpio_port = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&gpio_port->gpio_chip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver ltq_gpio_driver = {
|
||||
.probe = ltq_gpio_probe,
|
||||
.remove = __devexit_p(ltq_gpio_remove),
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int __init ltq_gpio_init(void)
|
||||
{
|
||||
int ret = platform_driver_register(<q_gpio_driver);
|
||||
if (ret)
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": Error registering platform driver!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
postcore_initcall(ltq_gpio_init);
|
||||
|
||||
/**
|
||||
* Convert interrupt number to corresponding port/pin pair
|
||||
* Returns the port/pin pair serving the selected external interrupt;
|
||||
* needed since mapping not linear.
|
||||
*
|
||||
* \param exint External interrupt number
|
||||
* \param port Pointer for resulting port
|
||||
* \param pin Pointer for resutling pin
|
||||
* \return -EINVAL Invalid exint
|
||||
* \return 0 port/pin updated
|
||||
* \ingroup API
|
||||
*/
|
||||
static int ltq_exint2port(u32 exint, int *port, int *pin)
|
||||
{
|
||||
if ((exint >= 0) && (exint <= 10)) {
|
||||
*port = 0;
|
||||
*pin = exint + 7;
|
||||
} else if ((exint >= 11) && (exint <= 14)) {
|
||||
*port = 1;
|
||||
*pin = 18 - (exint - 11) ;
|
||||
} else if (exint == 15) {
|
||||
*port = 1;
|
||||
*pin = 19;
|
||||
} else if (exint == 16) {
|
||||
*port = 0;
|
||||
*pin = 19;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable external interrupt.
|
||||
* This function enables an external interrupt and sets the given mode.
|
||||
* valid values for mode are:
|
||||
* - 0 = Interrupt generation disabled
|
||||
* - 1 = Interrupt on rising edge
|
||||
* - 2 = Interrupt on falling edge
|
||||
* - 3 = Interrupt on rising and falling edge
|
||||
* - 5 = Interrupt on high level detection
|
||||
* - 6 = Interrupt on low level detection
|
||||
*
|
||||
* \param exint - Number of external interrupt
|
||||
* \param mode - Trigger mode
|
||||
* \return 0 on success
|
||||
* \ingroup API
|
||||
*/
|
||||
int ifx_enable_external_int(u32 exint, u32 mode)
|
||||
{
|
||||
int port;
|
||||
int pin;
|
||||
|
||||
if ((mode < 0) || (mode > 6))
|
||||
return -EINVAL;
|
||||
|
||||
if (ltq_exint2port(exint, &port, &pin))
|
||||
return -EINVAL;
|
||||
|
||||
ltq_port_clear_exintcr0(port, pin);
|
||||
ltq_port_clear_exintcr1(port, pin);
|
||||
ltq_port_clear_irncfg(port, pin);
|
||||
|
||||
if (mode & 0x1)
|
||||
ltq_port_set_exintcr0(port, pin);
|
||||
if (mode & 0x2)
|
||||
ltq_port_set_exintcr1(port, pin);
|
||||
if (mode & 0x4)
|
||||
ltq_port_set_irncfg(port, pin);
|
||||
|
||||
ltq_port_set_irnen(port, pin);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ifx_enable_external_int);
|
||||
|
||||
/**
|
||||
* Disable external interrupt.
|
||||
* This function disables an external interrupt and sets mode to 0x00.
|
||||
*
|
||||
* \param exint - Number of external interrupt
|
||||
* \return 0 on success
|
||||
* \ingroup API
|
||||
*/
|
||||
int ifx_disable_external_int(u32 exint)
|
||||
{
|
||||
int port;
|
||||
int pin;
|
||||
|
||||
if (ltq_exint2port(exint, &port, &pin))
|
||||
return -EINVAL;
|
||||
|
||||
ltq_port_clear_irnen(port, pin);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ifx_disable_external_int);
|
||||
@@ -0,0 +1,73 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_buttons.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include "../machtypes.h"
|
||||
|
||||
#include <sys1_reg.h>
|
||||
#include <sys2_reg.h>
|
||||
#include <svip_pms.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
static const struct ltq_mux_pin mux_p0[LTQ_MUX_P0_PINS] = {
|
||||
LTQ_MUX_P0_0_SSC0_MTSR,
|
||||
LTQ_MUX_P0_1_SSC0_MRST,
|
||||
LTQ_MUX_P0_2_SSC0_SCLK,
|
||||
LTQ_MUX_P0_3_SSC1_MTSR,
|
||||
LTQ_MUX_P0_4_SSC1_MRST,
|
||||
LTQ_MUX_P0_5_SSC1_SCLK,
|
||||
LTQ_MUX_P0_6_SSC0_CS0,
|
||||
LTQ_MUX_P0_7_SSC0_CS1,
|
||||
LTQ_MUX_P0_8_SSC0_CS2,
|
||||
LTQ_MUX_P0_9,
|
||||
LTQ_MUX_P0_10,
|
||||
LTQ_MUX_P0_11_EXINT4,
|
||||
LTQ_MUX_P0_12,
|
||||
LTQ_MUX_P0_13,
|
||||
LTQ_MUX_P0_14_ASC0_TXD,
|
||||
LTQ_MUX_P0_15_ASC0_RXD,
|
||||
LTQ_MUX_P0_16_EXINT9,
|
||||
LTQ_MUX_P0_17_EXINT10,
|
||||
LTQ_MUX_P0_18_EJ_BRKIN,
|
||||
LTQ_MUX_P0_19_EXINT16
|
||||
};
|
||||
|
||||
static void __init easy33016_init(void)
|
||||
{
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_L2C |
|
||||
SYS1_CLKENR_DDR2 |
|
||||
SYS1_CLKENR_SMI2 |
|
||||
SYS1_CLKENR_SMI1 |
|
||||
SYS1_CLKENR_SMI0 |
|
||||
SYS1_CLKENR_FMI0 |
|
||||
SYS1_CLKENR_DMA |
|
||||
SYS1_CLKENR_SSC0 |
|
||||
SYS1_CLKENR_SSC1 |
|
||||
SYS1_CLKENR_EBU);
|
||||
|
||||
svip_sys2_clk_enable(SYS2_CLKENR_HWSYNC |
|
||||
SYS2_CLKENR_MBS |
|
||||
SYS2_CLKENR_SWINT);
|
||||
|
||||
svip_register_mux(mux_p0, NULL, NULL, NULL, NULL);
|
||||
svip_register_asc(0);
|
||||
svip_register_eth();
|
||||
svip_register_virtual_eth();
|
||||
ltq_register_wdt();
|
||||
svip_register_gpio();
|
||||
svip_register_spi();
|
||||
svip_register_nand();
|
||||
}
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY33016,
|
||||
"EASY33016",
|
||||
"EASY33016",
|
||||
easy33016_init);
|
||||
221
target/linux/lantiq/files/arch/mips/lantiq/svip/mach-easy336.c
Normal file
221
target/linux/lantiq/files/arch/mips/lantiq/svip/mach-easy336.c
Normal file
@@ -0,0 +1,221 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_buttons.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include "../machtypes.h"
|
||||
|
||||
#include <sys1_reg.h>
|
||||
#include <sys2_reg.h>
|
||||
#include <svip_pms.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
static struct mtd_partition easy336_sflash_partitions[] = {
|
||||
{
|
||||
.name = "SPI flash",
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
.offset = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct flash_platform_data easy336_sflash_data = {
|
||||
.name = "m25p32",
|
||||
.parts = (void *)&easy336_sflash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(easy336_sflash_partitions),
|
||||
.type = "m25p32",
|
||||
};
|
||||
|
||||
static struct spi_board_info bdinfo[] __initdata = {
|
||||
{
|
||||
.modalias = "m25p80",
|
||||
.platform_data = &easy336_sflash_data,
|
||||
.mode = SPI_MODE_0,
|
||||
.irq = -1,
|
||||
.max_speed_hz = 25000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
}
|
||||
};
|
||||
|
||||
static struct mtd_partition easy336_partitions[] = {
|
||||
{
|
||||
.name = "uboot",
|
||||
.offset = 0x0,
|
||||
.size = 0x40000,
|
||||
},
|
||||
{
|
||||
.name = "uboot_env",
|
||||
.offset = 0x40000,
|
||||
.size = 0x20000,
|
||||
},
|
||||
{
|
||||
.name = "linux",
|
||||
.offset = 0x60000,
|
||||
.size = 0x1a0000,
|
||||
},
|
||||
{
|
||||
.name = "rootfs",
|
||||
.offset = 0x200000,
|
||||
.size = 0x500000,
|
||||
},
|
||||
};
|
||||
|
||||
static struct physmap_flash_data easy336_flash_data = {
|
||||
.nr_parts = ARRAY_SIZE(easy336_partitions),
|
||||
.parts = easy336_partitions,
|
||||
};
|
||||
|
||||
static const struct ltq_mux_pin mux_p0[LTQ_MUX_P0_PINS] = {
|
||||
LTQ_MUX_P0_0_SSC0_MTSR,
|
||||
LTQ_MUX_P0_1_SSC0_MRST,
|
||||
LTQ_MUX_P0_2_SSC0_SCLK,
|
||||
LTQ_MUX_P0_3_SSC1_MTSR,
|
||||
LTQ_MUX_P0_4_SSC1_MRST,
|
||||
LTQ_MUX_P0_5_SSC1_SCLK,
|
||||
LTQ_MUX_P0_6_SSC0_CS0,
|
||||
LTQ_MUX_P0_7_SSC0_CS1,
|
||||
LTQ_MUX_P0_8_SSC0_CS2,
|
||||
LTQ_MUX_P0_9_SSC0_CS3,
|
||||
LTQ_MUX_P0_10_SSC0_CS4,
|
||||
LTQ_MUX_P0_11_SSC0_CS5,
|
||||
LTQ_MUX_P0_12_EXINT5,
|
||||
LTQ_MUX_P0_13_EXINT6,
|
||||
LTQ_MUX_P0_14_ASC0_TXD,
|
||||
LTQ_MUX_P0_15_ASC0_RXD,
|
||||
LTQ_MUX_P0_16_EXINT9,
|
||||
LTQ_MUX_P0_17_EXINT10,
|
||||
LTQ_MUX_P0_18_EJ_BRKIN,
|
||||
LTQ_MUX_P0_19_EXINT16
|
||||
};
|
||||
|
||||
static const struct ltq_mux_pin mux_p2[LTQ_MUX_P2_PINS] = {
|
||||
LTQ_MUX_P2_0_EBU_A0,
|
||||
LTQ_MUX_P2_1_EBU_A1,
|
||||
LTQ_MUX_P2_2_EBU_A2,
|
||||
LTQ_MUX_P2_3_EBU_A3,
|
||||
LTQ_MUX_P2_4_EBU_A4,
|
||||
LTQ_MUX_P2_5_EBU_A5,
|
||||
LTQ_MUX_P2_6_EBU_A6,
|
||||
LTQ_MUX_P2_7_EBU_A7,
|
||||
LTQ_MUX_P2_8_EBU_A8,
|
||||
LTQ_MUX_P2_9_EBU_A9,
|
||||
LTQ_MUX_P2_10_EBU_A10,
|
||||
LTQ_MUX_P2_11_EBU_A11,
|
||||
LTQ_MUX_P2_12_EBU_RD,
|
||||
LTQ_MUX_P2_13_EBU_WR,
|
||||
LTQ_MUX_P2_14_EBU_ALE,
|
||||
LTQ_MUX_P2_15_EBU_WAIT,
|
||||
LTQ_MUX_P2_16_EBU_RDBY,
|
||||
LTQ_MUX_P2_17_EBU_BC0,
|
||||
LTQ_MUX_P2_18_EBU_BC1
|
||||
};
|
||||
|
||||
static const struct ltq_mux_pin mux_p3[LTQ_MUX_P3_PINS] = {
|
||||
LTQ_MUX_P3_0_EBU_AD0,
|
||||
LTQ_MUX_P3_1_EBU_AD1,
|
||||
LTQ_MUX_P3_2_EBU_AD2,
|
||||
LTQ_MUX_P3_3_EBU_AD3,
|
||||
LTQ_MUX_P3_4_EBU_AD4,
|
||||
LTQ_MUX_P3_5_EBU_AD5,
|
||||
LTQ_MUX_P3_6_EBU_AD6,
|
||||
LTQ_MUX_P3_7_EBU_AD7,
|
||||
LTQ_MUX_P3_8_EBU_AD8,
|
||||
LTQ_MUX_P3_9_EBU_AD9,
|
||||
LTQ_MUX_P3_10_EBU_AD10,
|
||||
LTQ_MUX_P3_11_EBU_AD11,
|
||||
LTQ_MUX_P3_12_EBU_AD12,
|
||||
LTQ_MUX_P3_13_EBU_AD13,
|
||||
LTQ_MUX_P3_14_EBU_AD14,
|
||||
LTQ_MUX_P3_15_EBU_AD15,
|
||||
LTQ_MUX_P3_16_EBU_CS0,
|
||||
LTQ_MUX_P3_17_EBU_CS1,
|
||||
LTQ_MUX_P3_18_EBU_CS2,
|
||||
LTQ_MUX_P3_19_EBU_CS3
|
||||
};
|
||||
|
||||
static void __init easy336_init_common(void)
|
||||
{
|
||||
svip_sys1_clk_enable(SYS1_CLKENR_L2C |
|
||||
SYS1_CLKENR_DDR2 |
|
||||
SYS1_CLKENR_SMI2 |
|
||||
SYS1_CLKENR_SMI1 |
|
||||
SYS1_CLKENR_SMI0 |
|
||||
SYS1_CLKENR_FMI0 |
|
||||
SYS1_CLKENR_DMA |
|
||||
SYS1_CLKENR_GPTC |
|
||||
SYS1_CLKENR_EBU);
|
||||
|
||||
svip_sys2_clk_enable(SYS2_CLKENR_HWSYNC |
|
||||
SYS2_CLKENR_MBS |
|
||||
SYS2_CLKENR_SWINT |
|
||||
SYS2_CLKENR_HWACC3 |
|
||||
SYS2_CLKENR_HWACC2 |
|
||||
SYS2_CLKENR_HWACC1 |
|
||||
SYS2_CLKENR_HWACC0 |
|
||||
SYS2_CLKENR_SIF7 |
|
||||
SYS2_CLKENR_SIF6 |
|
||||
SYS2_CLKENR_SIF5 |
|
||||
SYS2_CLKENR_SIF4 |
|
||||
SYS2_CLKENR_SIF3 |
|
||||
SYS2_CLKENR_SIF2 |
|
||||
SYS2_CLKENR_SIF1 |
|
||||
SYS2_CLKENR_SIF0 |
|
||||
SYS2_CLKENR_DFEV7 |
|
||||
SYS2_CLKENR_DFEV6 |
|
||||
SYS2_CLKENR_DFEV5 |
|
||||
SYS2_CLKENR_DFEV4 |
|
||||
SYS2_CLKENR_DFEV3 |
|
||||
SYS2_CLKENR_DFEV2 |
|
||||
SYS2_CLKENR_DFEV1 |
|
||||
SYS2_CLKENR_DFEV0);
|
||||
|
||||
svip_register_mux(mux_p0, NULL, mux_p2, mux_p3, NULL);
|
||||
svip_register_asc(0);
|
||||
svip_register_eth();
|
||||
svip_register_virtual_eth();
|
||||
/* ltq_register_wdt(); - conflicts with lq_switch */
|
||||
svip_register_gpio();
|
||||
svip_register_spi();
|
||||
ltq_register_tapi();
|
||||
}
|
||||
|
||||
static void __init easy336_init(void)
|
||||
{
|
||||
easy336_init_common();
|
||||
ltq_register_nor(&easy336_flash_data);
|
||||
}
|
||||
|
||||
static void __init easy336sf_init(void)
|
||||
{
|
||||
easy336_init_common();
|
||||
svip_register_spi_flash(bdinfo);
|
||||
}
|
||||
|
||||
static void __init easy336nand_init(void)
|
||||
{
|
||||
easy336_init_common();
|
||||
svip_register_nand();
|
||||
}
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY336,
|
||||
"EASY336",
|
||||
"EASY336",
|
||||
easy336_init);
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY336SF,
|
||||
"EASY336SF",
|
||||
"EASY336 (Serial Flash)",
|
||||
easy336sf_init);
|
||||
|
||||
MIPS_MACHINE(LANTIQ_MACH_EASY336NAND,
|
||||
"EASY336NAND",
|
||||
"EASY336 (NAND Flash)",
|
||||
easy336nand_init);
|
||||
|
||||
187
target/linux/lantiq/files/arch/mips/lantiq/svip/mux.c
Normal file
187
target/linux/lantiq/files/arch/mips/lantiq/svip/mux.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/************************************************************************
|
||||
*
|
||||
* Copyright (c) 2007
|
||||
* Infineon Technologies AG
|
||||
* St. Martin Strasse 53; 81669 Muenchen; Germany
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <svip_mux.h>
|
||||
#include <sys1_reg.h>
|
||||
#include <sys2_reg.h>
|
||||
#include <svip_pms.h>
|
||||
|
||||
#define DRV_NAME "ltq_mux"
|
||||
|
||||
static void ltq_mux_port_init(const int port,
|
||||
const struct ltq_mux_pin *pins,
|
||||
const int pin_max)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < pin_max; i++)
|
||||
ltq_gpio_configure(port,
|
||||
i,
|
||||
pins[i].dirin,
|
||||
pins[i].puen,
|
||||
pins[i].altsel0,
|
||||
pins[i].altsel1);
|
||||
}
|
||||
|
||||
static int ltq_mux_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ltq_mux_settings *mux_settings = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (mux_settings->mux_p0)
|
||||
ltq_mux_port_init(0,
|
||||
mux_settings->mux_p0,
|
||||
LTQ_MUX_P0_PINS);
|
||||
|
||||
if (mux_settings->mux_p1)
|
||||
ltq_mux_port_init(1,
|
||||
mux_settings->mux_p1,
|
||||
LTQ_MUX_P1_PINS);
|
||||
|
||||
if (mux_settings->mux_p2)
|
||||
ltq_mux_port_init(2,
|
||||
mux_settings->mux_p2,
|
||||
LTQ_MUX_P2_PINS);
|
||||
|
||||
if (mux_settings->mux_p3)
|
||||
ltq_mux_port_init(3,
|
||||
mux_settings->mux_p3,
|
||||
LTQ_MUX_P3_PINS);
|
||||
|
||||
if (mux_settings->mux_p4)
|
||||
ltq_mux_port_init(4,
|
||||
mux_settings->mux_p4,
|
||||
LTQ_MUX_P4_PINS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ltq_mux_read_procmem(char *buf, char **start, off_t offset,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len = 0;
|
||||
int t = 0, i = 0;
|
||||
u32 port_clk[5] = {
|
||||
SYS1_CLKENR_PORT0,
|
||||
SYS1_CLKENR_PORT1,
|
||||
SYS1_CLKENR_PORT2,
|
||||
SYS1_CLKENR_PORT3,
|
||||
SYS2_CLKENR_PORT4,
|
||||
};
|
||||
|
||||
#define PROC_PRINT(fmt, args...) \
|
||||
do { \
|
||||
int c_len = 0; \
|
||||
c_len = snprintf(buf + len, count - len, fmt, ## args); \
|
||||
if (c_len <= 0) \
|
||||
goto out; \
|
||||
if (c_len >= (count - len)) { \
|
||||
len += (count - len); \
|
||||
goto out; \
|
||||
} \
|
||||
len += c_len; \
|
||||
if (offset > 0) { \
|
||||
if (len > offset) { \
|
||||
len -= offset; \
|
||||
memmove(buf, buf + offset, len); \
|
||||
offset = 0; \
|
||||
} else { \
|
||||
offset -= len; \
|
||||
len = 0; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
PROC_PRINT("\nVINETIC-SVIP Multiplex Settings\n");
|
||||
PROC_PRINT(" 3 2 1 0\n");
|
||||
PROC_PRINT(" 10987654321098765432109876543210\n");
|
||||
PROC_PRINT(" --------------------------------\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(port_clk); i++) {
|
||||
if (i < 4) {
|
||||
if (!svip_sys1_clk_is_enabled(port_clk[i]))
|
||||
continue;
|
||||
} else {
|
||||
if (!svip_sys2_clk_is_enabled(port_clk[i]))
|
||||
continue;
|
||||
}
|
||||
|
||||
PROC_PRINT("P%d.%-10s", i, "DIR:");
|
||||
|
||||
for (t = 31; t != -1; t--)
|
||||
PROC_PRINT("%d", ltq_port_get_dir(i, t) == 1 ? 1 : 0);
|
||||
PROC_PRINT("\n");
|
||||
|
||||
PROC_PRINT("P%d.%-10s", i, "PUEN:");
|
||||
for (t = 31; t != -1; t--)
|
||||
PROC_PRINT("%d", ltq_port_get_puden(i, t) == 1 ? 1 : 0);
|
||||
PROC_PRINT("\n");
|
||||
|
||||
PROC_PRINT("P%d.%-10s", i, "ALTSEL0:");
|
||||
for (t = 31; t != -1; t--)
|
||||
PROC_PRINT("%d",
|
||||
ltq_port_get_altsel0(i, t) == 1 ? 1 : 0);
|
||||
PROC_PRINT("\n");
|
||||
|
||||
PROC_PRINT("P%d.%-10s", i, "ALTSEL1:");
|
||||
for (t = 31; t != -1; t--)
|
||||
PROC_PRINT("%d",
|
||||
ltq_port_get_altsel1(i, t) == 1 ? 1 : 0);
|
||||
PROC_PRINT("\n\n");
|
||||
}
|
||||
|
||||
out:
|
||||
if (len < 0) {
|
||||
len = 0;
|
||||
*eof = 1;
|
||||
} else if (len < count) {
|
||||
*eof = 1;
|
||||
} else {
|
||||
len = count;
|
||||
}
|
||||
|
||||
*start = buf;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static struct platform_driver ltq_mux_driver = {
|
||||
.probe = ltq_mux_probe,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int __init ltq_mux_init(void)
|
||||
{
|
||||
int ret = platform_driver_register(<q_mux_driver);
|
||||
if (ret) {
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": Error registering platform driver!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return create_proc_read_entry("driver/ltq_mux", 0, NULL,
|
||||
ltq_mux_read_procmem, NULL) == NULL;
|
||||
}
|
||||
|
||||
module_init(ltq_mux_init);
|
||||
101
target/linux/lantiq/files/arch/mips/lantiq/svip/pms.c
Normal file
101
target/linux/lantiq/files/arch/mips/lantiq/svip/pms.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/************************************************************************
|
||||
*
|
||||
* Copyright (c) 2007
|
||||
* Infineon Technologies AG
|
||||
* St. Martin Strasse 53; 81669 Muenchen; Germany
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/addrspace.h>
|
||||
|
||||
#include <base_reg.h>
|
||||
#include <sys1_reg.h>
|
||||
#include <sys2_reg.h>
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
static struct svip_reg_sys1 *const sys1 = (struct svip_reg_sys1 *)LTQ_SYS1_BASE;
|
||||
static struct svip_reg_sys2 *const sys2 = (struct svip_reg_sys2 *)LTQ_SYS2_BASE;
|
||||
|
||||
void svip_sys1_clk_enable(u32 mask)
|
||||
{
|
||||
sys1_w32(sys1_r32(clksr) | mask, clkenr);
|
||||
asm("sync;");
|
||||
}
|
||||
EXPORT_SYMBOL(svip_sys1_clk_enable);
|
||||
|
||||
int svip_sys1_clk_is_enabled(u32 mask)
|
||||
{
|
||||
return (sys1_r32(clksr) & mask) != 0;
|
||||
}
|
||||
EXPORT_SYMBOL(svip_sys1_clk_is_enabled);
|
||||
|
||||
void svip_sys2_clk_enable(u32 mask)
|
||||
{
|
||||
sys2_w32(sys2_r32(clksr) | mask, clkenr);
|
||||
asm("sync;");
|
||||
}
|
||||
EXPORT_SYMBOL(svip_sys2_clk_enable);
|
||||
|
||||
int svip_sys2_clk_is_enabled(u32 mask)
|
||||
{
|
||||
return (sys2_r32(clksr) & mask) != 0;
|
||||
}
|
||||
EXPORT_SYMBOL(svip_sys2_clk_is_enabled);
|
||||
|
||||
int ltq_pms_read_procmem(char *buf, char **start, off_t offset,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
long len = 0;
|
||||
int t = 0;
|
||||
u32 bit = 0;
|
||||
u32 reg_tmp, bits_tmp;
|
||||
|
||||
len = sprintf(buf, "\nSVIP PMS Settings\n");
|
||||
len = len + sprintf(buf + len,
|
||||
" 3 2 1 0\n");
|
||||
len = len + sprintf(buf + len,
|
||||
" 210987654321098765432109876543210\n");
|
||||
len = len + sprintf(buf + len,
|
||||
"---------------------------------------------\n");
|
||||
len = len + sprintf(buf + len,
|
||||
"SYS1_CLKSR: ");
|
||||
reg_tmp = sys1_r32(clksr);
|
||||
bit = 0x80000000;
|
||||
for (t = 31; t != -1; t--) {
|
||||
bits_tmp = (reg_tmp & bit) >> t;
|
||||
len = len + sprintf(buf + len, "%d", bits_tmp);
|
||||
bit = bit >> 1;
|
||||
}
|
||||
len = len + sprintf(buf + len, "\n\n");
|
||||
len = len + sprintf(buf + len, "SYS2_CLKSR: ");
|
||||
reg_tmp = sys2_r32(clksr);
|
||||
bit = 0x80000000;
|
||||
for (t = 31; t != -1; t--) {
|
||||
bits_tmp = (reg_tmp & bit) >> t;
|
||||
len = len + sprintf(buf + len, "%d", bits_tmp);
|
||||
bit = bit >> 1;
|
||||
}
|
||||
len = len + sprintf(buf + len, "\n\n");
|
||||
|
||||
*eof = 1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int __init ltq_pms_init_proc(void)
|
||||
{
|
||||
return create_proc_read_entry("driver/ltq_pms", 0, NULL,
|
||||
ltq_pms_read_procmem, NULL) == NULL;
|
||||
}
|
||||
|
||||
module_init(ltq_pms_init_proc);
|
||||
73
target/linux/lantiq/files/arch/mips/lantiq/svip/prom.c
Normal file
73
target/linux/lantiq/files/arch/mips/lantiq/svip/prom.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/time.h>
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "../prom.h"
|
||||
#include "../clk.h"
|
||||
#include "../machtypes.h"
|
||||
|
||||
#include <base_reg.h>
|
||||
#include <ebu_reg.h>
|
||||
|
||||
#define SOC_SVIP "SVIP"
|
||||
|
||||
#define PART_SHIFT 12
|
||||
#define PART_MASK 0x0FFFF000
|
||||
#define REV_SHIFT 28
|
||||
#define REV_MASK 0xF0000000
|
||||
|
||||
static struct svip_reg_ebu *const ebu = (struct svip_reg_ebu *)LTQ_EBU_BASE;
|
||||
|
||||
void __init ltq_soc_init(void)
|
||||
{
|
||||
clkdev_add_static(ltq_svip_cpu_hz(), ltq_svip_fpi_hz(),
|
||||
ltq_svip_io_region_clock());
|
||||
}
|
||||
|
||||
void __init
|
||||
ltq_soc_setup(void)
|
||||
{
|
||||
if (mips_machtype == LANTIQ_MACH_EASY33016 ||
|
||||
mips_machtype == LANTIQ_MACH_EASY336) {
|
||||
ebu_w32(0x120000f1, addr_sel_2);
|
||||
ebu_w32(LTQ_EBU_CON_0_ADSWP |
|
||||
LTQ_EBU_CON_0_SETUP |
|
||||
LTQ_EBU_CON_0_BCGEN_VAL(0x02) |
|
||||
LTQ_EBU_CON_0_WAITWRC_VAL(7) |
|
||||
LTQ_EBU_CON_0_WAITRDC_VAL(3) |
|
||||
LTQ_EBU_CON_0_HOLDC_VAL(3) |
|
||||
LTQ_EBU_CON_0_RECOVC_VAL(3) |
|
||||
LTQ_EBU_CON_0_CMULT_VAL(3), con_2);
|
||||
}
|
||||
}
|
||||
|
||||
void __init
|
||||
ltq_soc_detect(struct ltq_soc_info *i)
|
||||
{
|
||||
i->partnum = (ltq_r32(LTQ_STATUS_CHIPID) & PART_MASK) >> PART_SHIFT;
|
||||
i->rev = (ltq_r32(LTQ_STATUS_CHIPID) & REV_MASK) >> REV_SHIFT;
|
||||
sprintf(i->rev_type, "1.%d", i->rev);
|
||||
switch (i->partnum) {
|
||||
case SOC_ID_SVIP:
|
||||
i->name = SOC_SVIP;
|
||||
i->type = SOC_TYPE_SVIP;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "unknown partnum : 0x%08X\n", i->partnum);
|
||||
while (1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
95
target/linux/lantiq/files/arch/mips/lantiq/svip/reset.c
Normal file
95
target/linux/lantiq/files/arch/mips/lantiq/svip/reset.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/reboot.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include "../machtypes.h"
|
||||
#include <base_reg.h>
|
||||
#include <sys1_reg.h>
|
||||
#include <boot_reg.h>
|
||||
#include <ebu_reg.h>
|
||||
|
||||
static struct svip_reg_sys1 *const sys1 = (struct svip_reg_sys1 *)LTQ_SYS1_BASE;
|
||||
static struct svip_reg_ebu *const ebu = (struct svip_reg_ebu *)LTQ_EBU_BASE;
|
||||
|
||||
#define CPLD_CMDREG3 ((volatile unsigned char*)(KSEG1 + 0x120000f3))
|
||||
extern void switchip_reset(void);
|
||||
|
||||
static void ltq_machine_restart(char *command)
|
||||
{
|
||||
printk(KERN_NOTICE "System restart\n");
|
||||
local_irq_disable();
|
||||
|
||||
if (mips_machtype == LANTIQ_MACH_EASY33016 ||
|
||||
mips_machtype == LANTIQ_MACH_EASY336) {
|
||||
/* We just use the CPLD function to reset the entire system as a
|
||||
workaround for the switch reset problem */
|
||||
local_irq_disable();
|
||||
ebu_w32(0x120000f1, addr_sel_2);
|
||||
ebu_w32(0x404027ff, con_2);
|
||||
|
||||
if (mips_machtype == LANTIQ_MACH_EASY336)
|
||||
/* set bit 0 to reset SVIP */
|
||||
*CPLD_CMDREG3 = (1<<0);
|
||||
else
|
||||
/* set bit 7 to reset SVIP, set bit 3 to reset xT */
|
||||
*CPLD_CMDREG3 = (1<<7) | (1<<3);
|
||||
} else {
|
||||
*LTQ_BOOT_RVEC(0) = 0;
|
||||
/* reset all except PER, SUBSYS and CPU0 */
|
||||
sys1_w32(0x00043F3E, rreqr);
|
||||
/* release WDT0 reset */
|
||||
sys1_w32(0x00000100, rrlsr);
|
||||
/* restore reset value for clock enables */
|
||||
sys1_w32(~0x0c000040, clkclr);
|
||||
/* reset SUBSYS (incl. DDR2) and CPU0 */
|
||||
sys1_w32(0x00030001, rbtr);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
static void ltq_machine_halt(void)
|
||||
{
|
||||
printk(KERN_NOTICE "System halted.\n");
|
||||
local_irq_disable();
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
static void ltq_machine_power_off(void)
|
||||
{
|
||||
printk(KERN_NOTICE "Please turn off the power now.\n");
|
||||
local_irq_disable();
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
/* This function is used by the watchdog driver */
|
||||
int ltq_reset_cause(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ltq_reset_cause);
|
||||
|
||||
static int __init mips_reboot_setup(void)
|
||||
{
|
||||
_machine_restart = ltq_machine_restart;
|
||||
_machine_halt = ltq_machine_halt;
|
||||
pm_power_off = ltq_machine_power_off;
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(mips_reboot_setup);
|
||||
666
target/linux/lantiq/files/arch/mips/lantiq/svip/switchip_setup.c
Normal file
666
target/linux/lantiq/files/arch/mips/lantiq/svip/switchip_setup.c
Normal file
@@ -0,0 +1,666 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) 2007, Infineon Technologies. All rights reserved.
|
||||
|
||||
No Warranty
|
||||
Because the program is licensed free of charge, there is no warranty for
|
||||
the program, to the extent permitted by applicable law. Except when
|
||||
otherwise stated in writing the copyright holders and/or other parties
|
||||
provide the program "as is" without warranty of any kind, either
|
||||
expressed or implied, including, but not limited to, the implied
|
||||
warranties of merchantability and fitness for a particular purpose. The
|
||||
entire risk as to the quality and performance of the program is with
|
||||
you. should the program prove defective, you assume the cost of all
|
||||
necessary servicing, repair or correction.
|
||||
|
||||
In no event unless required by applicable law or agreed to in writing
|
||||
will any copyright holder, or any other party who may modify and/or
|
||||
redistribute the program as permitted above, be liable to you for
|
||||
damages, including any general, special, incidental or consequential
|
||||
damages arising out of the use or inability to use the program
|
||||
(including but not limited to loss of data or data being rendered
|
||||
inaccurate or losses sustained by you or third parties or a failure of
|
||||
the program to operate with any other programs), even if such holder or
|
||||
other party has been advised of the possibility of such damages.
|
||||
******************************************************************************
|
||||
Module : switchip_setup.c
|
||||
Date : 2007-11-09
|
||||
Description : Basic setup of embedded ethernet switch "SwitchIP"
|
||||
Remarks: andreas.schmidt@infineon.com
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/* TODO: get rid of #ifdef CONFIG_LANTIQ_MACH_EASY336 */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <base_reg.h>
|
||||
#include <es_reg.h>
|
||||
#include <sys1_reg.h>
|
||||
#include <dma_reg.h>
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
static struct svip_reg_sys1 *const sys1 = (struct svip_reg_sys1 *)LTQ_SYS1_BASE;
|
||||
static struct svip_reg_es *const es = (struct svip_reg_es *)LTQ_ES_BASE;
|
||||
|
||||
/* PHY Organizationally Unique Identifier (OUI) */
|
||||
#define PHY_OUI_PMC 0x00E004
|
||||
#define PHY_OUI_VITESSE 0x008083
|
||||
#define PHY_OUI_DEFAULT 0xFFFFFF
|
||||
|
||||
unsigned short switchip_phy_read(unsigned int phyaddr, unsigned int regaddr);
|
||||
void switchip_phy_write(unsigned int phyaddr, unsigned int regaddr,
|
||||
unsigned short data);
|
||||
|
||||
static int phy_address[2] = {0, 1};
|
||||
static u32 phy_oui;
|
||||
static void switchip_mdio_poll_init(void);
|
||||
static void _switchip_mdio_poll(struct work_struct *work);
|
||||
|
||||
/* struct workqueue_struct mdio_poll_task; */
|
||||
static struct workqueue_struct *mdio_poll_workqueue;
|
||||
DECLARE_DELAYED_WORK(mdio_poll_work, _switchip_mdio_poll);
|
||||
static int old_link_status[2] = {-1, -1};
|
||||
|
||||
/**
|
||||
* Autonegotiation check.
|
||||
* This funtion checks for link changes. If a link change has occured it will
|
||||
* update certain switch registers.
|
||||
*/
|
||||
static void _switchip_check_phy_status(int port)
|
||||
{
|
||||
int new_link_status;
|
||||
unsigned short reg1;
|
||||
|
||||
reg1 = switchip_phy_read(phy_address[port], 1);
|
||||
if ((reg1 == 0xFFFF) || (reg1 == 0x0000))
|
||||
return; /* no PHY connected */
|
||||
|
||||
new_link_status = reg1 & 4;
|
||||
if (old_link_status[port] ^ new_link_status) {
|
||||
/* link status change */
|
||||
if (!new_link_status) {
|
||||
if (port == 0)
|
||||
es_w32_mask(LTQ_ES_P0_CTL_REG_FLP, 0, p0_ctl);
|
||||
else
|
||||
es_w32_mask(LTQ_ES_P0_CTL_REG_FLP, 0, p1_ctl);
|
||||
|
||||
/* read again; link bit is latched low! */
|
||||
reg1 = switchip_phy_read(phy_address[port], 1);
|
||||
new_link_status = reg1 & 4;
|
||||
}
|
||||
|
||||
if (new_link_status) {
|
||||
unsigned short reg0, reg4, reg5, reg9, reg10;
|
||||
int phy_pause, phy_speed, phy_duplex;
|
||||
int aneg_enable, aneg_cmpt;
|
||||
|
||||
reg0 = switchip_phy_read(phy_address[port], 0);
|
||||
reg4 = switchip_phy_read(phy_address[port], 4);
|
||||
aneg_enable = reg0 & 0x1000;
|
||||
aneg_cmpt = reg1 & 0x20;
|
||||
|
||||
if (aneg_enable && aneg_cmpt) {
|
||||
reg5 = switchip_phy_read(phy_address[port], 5);
|
||||
switch (phy_oui) {
|
||||
#ifdef CONFIG_LANTIQ_MACH_EASY336
|
||||
case PHY_OUI_PMC:
|
||||
/* PMC Sierra supports 1Gigabit FD,
|
||||
* only. On successful
|
||||
* auto-negotiation, we are sure this
|
||||
* is what the LP can. */
|
||||
phy_pause = ((reg4 & reg5) & 0x0080) >> 7;
|
||||
phy_speed = 2;
|
||||
phy_duplex = 1;
|
||||
break;
|
||||
#endif
|
||||
case PHY_OUI_VITESSE:
|
||||
case PHY_OUI_DEFAULT:
|
||||
reg9 = switchip_phy_read(phy_address[port], 9);
|
||||
reg10 = switchip_phy_read(phy_address[port], 10);
|
||||
|
||||
/* Check if advertise and partner
|
||||
* agree on pause */
|
||||
phy_pause = ((reg4 & reg5) & 0x0400) >> 10;
|
||||
|
||||
/* Find the best mode both partners
|
||||
* support
|
||||
* Priority: 1GB-FD, 1GB-HD, 100MB-FD,
|
||||
* 100MB-HD, 10MB-FD, 10MB-HD */
|
||||
phy_speed = ((((reg9<<2) & reg10)
|
||||
& 0x0c00) >> 6) |
|
||||
(((reg4 & reg5) & 0x01e0) >> 5);
|
||||
|
||||
if (phy_speed >= 0x0020) {
|
||||
phy_speed = 2;
|
||||
phy_duplex = 1;
|
||||
} else if (phy_speed >= 0x0010) {
|
||||
phy_speed = 2;
|
||||
phy_duplex = 0;
|
||||
} else if (phy_speed >= 0x0008) {
|
||||
phy_speed = 1;
|
||||
phy_duplex = 1;
|
||||
} else if (phy_speed >= 0x0004) {
|
||||
phy_speed = 1;
|
||||
phy_duplex = 0;
|
||||
} else if (phy_speed >= 0x0002) {
|
||||
phy_speed = 0;
|
||||
phy_duplex = 1;
|
||||
} else {
|
||||
phy_speed = 0;
|
||||
phy_duplex = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
phy_pause = (reg4 & 0x0400) >> 10;
|
||||
phy_speed = (reg0 & 0x40 ? 2 : (reg0 >> 13)&1);
|
||||
phy_duplex = (reg0 >> 8)&1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* parallel detection or fixed speed */
|
||||
phy_pause = (reg4 & 0x0400) >> 10;
|
||||
phy_speed = (reg0 & 0x40 ? 2 : (reg0 >> 13)&1);
|
||||
phy_duplex = (reg0 >> 8)&1;
|
||||
}
|
||||
|
||||
if (port == 0) {
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P0SPD,
|
||||
LTQ_ES_RGMII_CTL_REG_P0SPD_VAL(phy_speed),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P0DUP,
|
||||
LTQ_ES_RGMII_CTL_REG_P0DUP_VAL(phy_duplex),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P0FCE,
|
||||
LTQ_ES_RGMII_CTL_REG_P0FCE_VAL(phy_pause),
|
||||
rgmii_ctl);
|
||||
|
||||
es_w32_mask(0, LTQ_ES_P0_CTL_REG_FLP, p0_ctl);
|
||||
} else {
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P1SPD,
|
||||
LTQ_ES_RGMII_CTL_REG_P1SPD_VAL(phy_speed),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P1DUP,
|
||||
LTQ_ES_RGMII_CTL_REG_P1DUP_VAL(phy_duplex),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P1FCE,
|
||||
LTQ_ES_RGMII_CTL_REG_P0FCE_VAL(phy_pause),
|
||||
rgmii_ctl);
|
||||
|
||||
es_w32_mask(1, LTQ_ES_P0_CTL_REG_FLP, p1_ctl);
|
||||
}
|
||||
}
|
||||
}
|
||||
old_link_status[port] = new_link_status;
|
||||
}
|
||||
|
||||
static void _switchip_mdio_poll(struct work_struct *work)
|
||||
{
|
||||
if (es_r32(sw_gctl0) & LTQ_ES_SW_GCTL0_REG_SE) {
|
||||
_switchip_check_phy_status(0);
|
||||
_switchip_check_phy_status(1);
|
||||
}
|
||||
|
||||
queue_delayed_work(mdio_poll_workqueue, &mdio_poll_work, HZ/2);
|
||||
}
|
||||
|
||||
static void switchip_mdio_poll_init(void)
|
||||
{
|
||||
mdio_poll_workqueue = create_workqueue("SVIP MDIP poll");
|
||||
INIT_DELAYED_WORK(&mdio_poll_work, _switchip_mdio_poll);
|
||||
|
||||
queue_delayed_work(mdio_poll_workqueue, &mdio_poll_work, HZ/2);
|
||||
|
||||
}
|
||||
|
||||
unsigned short switchip_phy_read(unsigned int phyaddr, unsigned int regaddr)
|
||||
{
|
||||
/* TODO: protect MDIO access with semaphore */
|
||||
es_w32(LTQ_ES_MDIO_CTL_REG_MBUSY
|
||||
| LTQ_ES_MDIO_CTL_REG_OP_VAL(2) /* read operation */
|
||||
| LTQ_ES_MDIO_CTL_REG_PHYAD_VAL(phyaddr)
|
||||
| LTQ_ES_MDIO_CTL_REG_REGAD_VAL(regaddr), mdio_ctl);
|
||||
while (es_r32(mdio_ctl) & LTQ_ES_MDIO_CTL_REG_MBUSY);
|
||||
|
||||
return es_r32(mdio_data) & 0xFFFF;
|
||||
}
|
||||
EXPORT_SYMBOL(switchip_phy_read);
|
||||
|
||||
void switchip_phy_write(unsigned int phyaddr, unsigned int regaddr,
|
||||
unsigned short data)
|
||||
{
|
||||
/* TODO: protect MDIO access with semaphore */
|
||||
es_w32(LTQ_ES_MDIO_CTL_REG_WD_VAL(data)
|
||||
| LTQ_ES_MDIO_CTL_REG_MBUSY
|
||||
| LTQ_ES_MDIO_CTL_REG_OP_VAL(1) /* write operation */
|
||||
| LTQ_ES_MDIO_CTL_REG_PHYAD_VAL(phyaddr)
|
||||
| LTQ_ES_MDIO_CTL_REG_REGAD_VAL(regaddr), mdio_ctl);
|
||||
while (es_r32(mdio_ctl) & LTQ_ES_MDIO_CTL_REG_MBUSY);
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(switchip_phy_write);
|
||||
|
||||
const static u32 switch_reset_offset_000[] = {
|
||||
/*b8000000:*/ 0xffffffff, 0x00000001, 0x00000001, 0x00000003,
|
||||
/*b8000010:*/ 0x04070001, 0x04070001, 0x04070001, 0xffffffff,
|
||||
/*b8000020:*/ 0x00001be8, 0x00001be8, 0x00001be8, 0xffffffff,
|
||||
/*b8000030:*/ 0x00000000, 0x00000000, 0x00080004, 0x00020001,
|
||||
/*b8000040:*/ 0x00000000, 0x00000000, 0x00080004, 0x00020001,
|
||||
/*b8000050:*/ 0x00000000, 0x00000000, 0x00080004, 0x00020001,
|
||||
/*b8000060:*/ 0x00000000, 0x00000000, 0x00081000, 0x001f7777,
|
||||
/*b8000070:*/ 0x00000000, 0x00000000, 0x0c00ac2b, 0x0000fa50,
|
||||
/*b8000080:*/ 0x00001000, 0x00001800, 0x00000000, 0x00000000,
|
||||
/*b8000090:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b80000a0:*/ 0x00000000, 0x00000050, 0x00000010, 0x00000000,
|
||||
/*b80000b0:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b80000c0:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b80000d0:*/ 0xffffffff, 0x00000000, 0x00000000
|
||||
};
|
||||
const static u32 switch_reset_offset_100[] = {
|
||||
/*b8000100:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000110:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000120:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000130:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000140:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000150:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000160:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000170:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000180:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b8000190:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b80001a0:*/ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
/*b80001b0:*/ 0x00000000, 0x00000000
|
||||
};
|
||||
|
||||
/*
|
||||
* Switch Reset.
|
||||
*/
|
||||
void switchip_reset(void)
|
||||
{
|
||||
volatile unsigned int *reg;
|
||||
volatile unsigned int rdreg;
|
||||
int i;
|
||||
|
||||
sys1_w32(SYS1_CLKENR_ETHSW, clkenr);
|
||||
asm("sync");
|
||||
|
||||
/* disable P0 */
|
||||
es_w32_mask(0, LTQ_ES_P0_CTL_REG_SPS_VAL(1), p0_ctl);
|
||||
/* disable P1 */
|
||||
es_w32_mask(0, LTQ_ES_P0_CTL_REG_SPS_VAL(1), p1_ctl);
|
||||
/* disable P2 */
|
||||
es_w32_mask(0, LTQ_ES_P0_CTL_REG_SPS_VAL(1), p2_ctl);
|
||||
|
||||
/**************************************
|
||||
* BEGIN: Procedure to clear MAC table
|
||||
**************************************/
|
||||
for (i = 0; i < 3; i++) {
|
||||
int result;
|
||||
|
||||
/* check if access engine is available */
|
||||
while (es_r32(adr_tb_st2) & LTQ_ES_ADR_TB_ST2_REG_BUSY);
|
||||
|
||||
/* initialise to first address */
|
||||
es_w32(LTQ_ES_ADR_TB_CTL2_REG_CMD_VAL(3)
|
||||
| LTQ_ES_ADR_TB_CTL2_REG_AC_VAL(0), adr_tb_ctl2);
|
||||
|
||||
/* wait while busy */
|
||||
while (es_r32(adr_tb_st2) & LTQ_ES_ADR_TB_ST2_REG_BUSY);
|
||||
|
||||
/* setup the portmap */
|
||||
es_w32_mask(0, LTQ_ES_ADR_TB_CTL1_REG_PMAP_VAL(1 << i),
|
||||
adr_tb_ctl1);
|
||||
|
||||
do {
|
||||
/* search for addresses by port */
|
||||
es_w32(LTQ_ES_ADR_TB_CTL2_REG_CMD_VAL(2)
|
||||
| LTQ_ES_ADR_TB_CTL2_REG_AC_VAL(9), adr_tb_ctl2);
|
||||
|
||||
/* wait while busy */
|
||||
while (es_r32(adr_tb_st2) & LTQ_ES_ADR_TB_ST2_REG_BUSY);
|
||||
|
||||
result = LTQ_ES_ADR_TB_ST2_REG_RSLT_GET(es_r32(adr_tb_st2));
|
||||
if (result == 0x101) {
|
||||
printk(KERN_ERR "%s, cmd error\n", __func__);
|
||||
return;
|
||||
}
|
||||
/* if Command OK, address found... */
|
||||
if (result == 0) {
|
||||
unsigned char mac[6];
|
||||
|
||||
mac[5] = (es_r32(adr_tb_st0) >> 0) & 0xff;
|
||||
mac[4] = (es_r32(adr_tb_st0) >> 8) & 0xff;
|
||||
mac[3] = (es_r32(adr_tb_st0) >> 16) & 0xff;
|
||||
mac[2] = (es_r32(adr_tb_st0) >> 24) & 0xff;
|
||||
mac[1] = (es_r32(adr_tb_st1) >> 0) & 0xff;
|
||||
mac[0] = (es_r32(adr_tb_st1) >> 8) & 0xff;
|
||||
|
||||
/* setup address */
|
||||
es_w32((mac[5] << 0) |
|
||||
(mac[4] << 8) |
|
||||
(mac[3] << 16) |
|
||||
(mac[2] << 24), adr_tb_ctl0);
|
||||
es_w32(LTQ_ES_ADR_TB_CTL1_REG_PMAP_VAL(1<<i) |
|
||||
LTQ_ES_ADR_TB_CTL1_REG_FID_VAL(0) |
|
||||
(mac[0] << 8) |
|
||||
(mac[1] << 0), adr_tb_ctl1);
|
||||
/* erase address */
|
||||
|
||||
es_w32(LTQ_ES_ADR_TB_CTL2_REG_CMD_VAL(1) |
|
||||
LTQ_ES_ADR_TB_CTL2_REG_AC_VAL(15),
|
||||
adr_tb_ctl2);
|
||||
|
||||
/* wait, while busy */
|
||||
while (es_r32(adr_tb_st2) &
|
||||
LTQ_ES_ADR_TB_ST2_REG_BUSY);
|
||||
}
|
||||
} while (result == 0);
|
||||
}
|
||||
/**************************************
|
||||
* END: Procedure to clear MAC table
|
||||
**************************************/
|
||||
|
||||
/* reset RMON counters */
|
||||
es_w32(LTQ_ES_RMON_CTL_REG_BAS | LTQ_ES_RMON_CTL_REG_CAC_VAL(3),
|
||||
rmon_ctl);
|
||||
|
||||
/* bring all registers to reset state */
|
||||
reg = LTQ_ES_PS_REG;
|
||||
for (i = 0; i < ARRAY_SIZE(switch_reset_offset_000); i++) {
|
||||
if ((reg == LTQ_ES_PS_REG) ||
|
||||
(reg >= LTQ_ES_ADR_TB_CTL0_REG &&
|
||||
reg <= LTQ_ES_ADR_TB_ST2_REG))
|
||||
continue;
|
||||
|
||||
if (switch_reset_offset_000[i] != 0xFFFFFFFF) {
|
||||
/* write reset value to register */
|
||||
*reg = switch_reset_offset_000[i];
|
||||
/* read register value back */
|
||||
rdreg = *reg;
|
||||
if (reg == LTQ_ES_SW_GCTL1_REG)
|
||||
rdreg &= ~LTQ_ES_SW_GCTL1_REG_BISTDN;
|
||||
/* compare read value with written one */
|
||||
if (rdreg != switch_reset_offset_000[i]) {
|
||||
printk(KERN_ERR "%s,%d: reg %08x mismatch "
|
||||
"[has:%08x, expect:%08x]\n",
|
||||
__func__, __LINE__,
|
||||
(unsigned int)reg, rdreg,
|
||||
switch_reset_offset_000[i]);
|
||||
}
|
||||
}
|
||||
reg++;
|
||||
}
|
||||
|
||||
reg = LTQ_ES_VLAN_FLT0_REG;
|
||||
for (i = 0; i < ARRAY_SIZE(switch_reset_offset_100); i++) {
|
||||
*reg = switch_reset_offset_100[i];
|
||||
rdreg = *reg;
|
||||
if (rdreg != switch_reset_offset_100[i]) {
|
||||
printk(KERN_ERR "%s,%d: reg %08x mismatch "
|
||||
"[has:%08x, expect:%08x]\n", __func__, __LINE__,
|
||||
(unsigned int)reg, rdreg,
|
||||
switch_reset_offset_100[i]);
|
||||
}
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(switchip_reset);
|
||||
|
||||
static u32 get_phy_oui(unsigned char phy_addr)
|
||||
{
|
||||
u32 oui;
|
||||
int i, bit, byte, shift, w;
|
||||
u16 reg_id[2];
|
||||
|
||||
/* read PHY identifier registers 1 and 2 */
|
||||
reg_id[0] = switchip_phy_read(phy_addr, 2);
|
||||
reg_id[1] = switchip_phy_read(phy_addr, 3);
|
||||
|
||||
oui = 0;
|
||||
w = 1;
|
||||
shift = 7;
|
||||
byte = 1;
|
||||
for (i = 0, bit = 10; i <= 21; i++, bit++) {
|
||||
oui |= ((reg_id[w] & (1<<bit)) ? 1 : 0) << shift;
|
||||
if (!(shift % 8)) {
|
||||
byte++;
|
||||
if (byte == 2)
|
||||
shift = 15;
|
||||
else
|
||||
shift = 21;
|
||||
} else {
|
||||
shift--;
|
||||
}
|
||||
if (w == 1 && bit == 15) {
|
||||
bit = -1;
|
||||
w = 0;
|
||||
}
|
||||
}
|
||||
return oui;
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch Initialization.
|
||||
*/
|
||||
int switchip_init(void)
|
||||
{
|
||||
int eth_port, phy_present = 0;
|
||||
u16 reg, mode;
|
||||
|
||||
sys1_w32(SYS1_CLKENR_ETHSW, clkenr);
|
||||
asm("sync");
|
||||
|
||||
/* Enable Switch, if not already done so */
|
||||
if ((es_r32(sw_gctl0) & LTQ_ES_SW_GCTL0_REG_SE) == 0)
|
||||
es_w32_mask(0, LTQ_ES_SW_GCTL0_REG_SE, sw_gctl0);
|
||||
/* Wait for completion of MBIST */
|
||||
while (LTQ_ES_SW_GCTL1_REG_BISTDN_GET(es_r32(sw_gctl1)) == 0);
|
||||
|
||||
switchip_reset();
|
||||
|
||||
mode = LTQ_ES_RGMII_CTL_REG_IS_GET(es_r32(rgmii_ctl));
|
||||
eth_port = (mode == 2 ? 1 : 0);
|
||||
|
||||
/* Set the primary port(port toward backplane) as sniffer port,
|
||||
changing from P2 which is the reset setting */
|
||||
es_w32_mask(LTQ_ES_SW_GCTL0_REG_SNIFFPN,
|
||||
LTQ_ES_SW_GCTL0_REG_SNIFFPN_VAL(eth_port),
|
||||
sw_gctl0);
|
||||
|
||||
/* Point MDIO state machine to invalid PHY addresses 8 and 9 */
|
||||
es_w32_mask(0, LTQ_ES_SW_GCTL0_REG_PHYBA, sw_gctl0);
|
||||
|
||||
/* Add CRC for packets from DMA to PMAC.
|
||||
Remove CRC for packets from PMAC to DMA. */
|
||||
es_w32(LTQ_ES_PMAC_HD_CTL_RC | LTQ_ES_PMAC_HD_CTL_AC, pmac_hd_ctl);
|
||||
|
||||
phy_oui = get_phy_oui(0);
|
||||
switch (phy_oui) {
|
||||
#ifdef CONFIG_LANTIQ_MACH_EASY336
|
||||
case PHY_OUI_PMC:
|
||||
phy_address[0] = (mode == 2 ? -1 : 2);
|
||||
phy_address[1] = (mode == 2 ? 2 : -1);
|
||||
break;
|
||||
#endif
|
||||
case PHY_OUI_VITESSE:
|
||||
default:
|
||||
phy_oui = PHY_OUI_DEFAULT;
|
||||
phy_address[0] = (mode == 2 ? 1 : 0);
|
||||
phy_address[1] = (mode == 2 ? 0 : 1);
|
||||
break;
|
||||
}
|
||||
|
||||
/****** PORT 0 *****/
|
||||
reg = switchip_phy_read(phy_address[0], 1);
|
||||
if ((reg != 0x0000) && (reg != 0xffff)) {
|
||||
/* PHY connected? */
|
||||
phy_present |= 1;
|
||||
/* Set Rx- and TxDelay in case of RGMII */
|
||||
switch (mode) {
|
||||
case 0: /* *RGMII,RGMII */
|
||||
case 2: /* RGMII,*GMII */
|
||||
/* program clock delay in PHY, not in SVIP */
|
||||
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P0RDLY, 0, rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P0TDLY, 0, rgmii_ctl);
|
||||
if (phy_oui == PHY_OUI_VITESSE ||
|
||||
phy_oui == PHY_OUI_DEFAULT) {
|
||||
switchip_phy_write(phy_address[0], 31, 0x0001);
|
||||
switchip_phy_write(phy_address[0], 28, 0xA000);
|
||||
switchip_phy_write(phy_address[0], 31, 0x0000);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (phy_oui == PHY_OUI_VITESSE ||
|
||||
phy_oui == PHY_OUI_DEFAULT) {
|
||||
/* Program PHY advertisements and
|
||||
* restart auto-negotiation */
|
||||
switchip_phy_write(phy_address[0], 4, 0x05E1);
|
||||
switchip_phy_write(phy_address[0], 9, 0x0300);
|
||||
switchip_phy_write(phy_address[0], 0, 0x3300);
|
||||
} else {
|
||||
reg = switchip_phy_read(phy_address[1], 0);
|
||||
reg |= 0x1000; /* auto-negotiation enable */
|
||||
switchip_phy_write(phy_address[1], 0, reg);
|
||||
reg |= 0x0200; /* auto-negotiation restart */
|
||||
switchip_phy_write(phy_address[1], 0, reg);
|
||||
}
|
||||
} else {
|
||||
/* Force SWITCH link with highest capability:
|
||||
* 100M FD for MII
|
||||
* 1G FD for GMII/RGMII
|
||||
*/
|
||||
switch (mode) {
|
||||
case 1: /* *MII,MII */
|
||||
case 3: /* *MII,RGMII */
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P0SPD_VAL(1),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P0DUP_VAL(1),
|
||||
rgmii_ctl);
|
||||
break;
|
||||
case 0: /* *RGMII,RGMII */
|
||||
case 2: /* RGMII,*GMII */
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P0SPD_VAL(2),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P0DUP_VAL(1),
|
||||
rgmii_ctl);
|
||||
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P0RDLY, 0, rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P0TDLY_VAL(2),
|
||||
rgmii_ctl);
|
||||
break;
|
||||
}
|
||||
|
||||
es_w32_mask(0, LTQ_ES_P0_CTL_REG_FLP, p0_ctl);
|
||||
}
|
||||
|
||||
/****** PORT 1 *****/
|
||||
reg = switchip_phy_read(phy_address[1], 1);
|
||||
if ((reg != 0x0000) && (reg != 0xffff)) {
|
||||
/* PHY connected? */
|
||||
phy_present |= 2;
|
||||
/* Set Rx- and TxDelay in case of RGMII */
|
||||
switch (mode) {
|
||||
case 0: /* *RGMII,RGMII */
|
||||
case 3: /* *MII,RGMII */
|
||||
/* program clock delay in PHY, not in SVIP */
|
||||
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P1RDLY, 0, rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P1TDLY, 0, rgmii_ctl);
|
||||
if (phy_oui == PHY_OUI_VITESSE ||
|
||||
phy_oui == PHY_OUI_DEFAULT) {
|
||||
switchip_phy_write(phy_address[1], 31, 0x0001);
|
||||
switchip_phy_write(phy_address[1], 28, 0xA000);
|
||||
switchip_phy_write(phy_address[1], 31, 0x0000);
|
||||
}
|
||||
break;
|
||||
case 2: /* RGMII,*GMII */
|
||||
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1SPD_VAL(2),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1DUP, rgmii_ctl);
|
||||
#ifdef CONFIG_LANTIQ_MACH_EASY336
|
||||
if (phy_oui == PHY_OUI_PMC) {
|
||||
switchip_phy_write(phy_address[1], 24, 0x0510);
|
||||
switchip_phy_write(phy_address[1], 17, 0xA38C);
|
||||
switchip_phy_write(phy_address[1], 17, 0xA384);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Program PHY advertisements and restart auto-negotiation */
|
||||
if (phy_oui == PHY_OUI_VITESSE ||
|
||||
phy_oui == PHY_OUI_DEFAULT) {
|
||||
switchip_phy_write(phy_address[1], 4, 0x05E1);
|
||||
switchip_phy_write(phy_address[1], 9, 0x0300);
|
||||
switchip_phy_write(phy_address[1], 0, 0x3300);
|
||||
} else {
|
||||
reg = switchip_phy_read(phy_address[1], 0);
|
||||
reg |= 0x1000; /* auto-negotiation enable */
|
||||
switchip_phy_write(phy_address[1], 0, reg);
|
||||
reg |= 0x0200; /* auto-negotiation restart */
|
||||
switchip_phy_write(phy_address[1], 0, reg);
|
||||
}
|
||||
} else {
|
||||
/* Force SWITCH link with highest capability:
|
||||
* 100M FD for MII
|
||||
* 1G FD for GMII/RGMII
|
||||
*/
|
||||
switch (mode) {
|
||||
case 1: /* *MII,MII */
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1SPD_VAL(1),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1DUP, rgmii_ctl);
|
||||
break;
|
||||
case 0: /* *RGMII,RGMII */
|
||||
case 3: /* *MII,RGMII */
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1SPD_VAL(2),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1DUP, rgmii_ctl);
|
||||
es_w32_mask(LTQ_ES_RGMII_CTL_REG_P1RDLY, 0, rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1TDLY_VAL(2),
|
||||
rgmii_ctl);
|
||||
break;
|
||||
case 2: /* RGMII,*GMII */
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1SPD_VAL(2),
|
||||
rgmii_ctl);
|
||||
es_w32_mask(0, LTQ_ES_RGMII_CTL_REG_P1DUP, rgmii_ctl);
|
||||
break;
|
||||
}
|
||||
es_w32_mask(0, LTQ_ES_P0_CTL_REG_FLP, p0_ctl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow unknown unicast/multicast and broadcasts
|
||||
* on all ports.
|
||||
*/
|
||||
|
||||
es_w32_mask(0, LTQ_ES_SW_GCTL1_REG_UP_VAL(7), sw_gctl1);
|
||||
es_w32_mask(0, LTQ_ES_SW_GCTL1_REG_BP_VAL(7), sw_gctl1);
|
||||
es_w32_mask(0, LTQ_ES_SW_GCTL1_REG_MP_VAL(7), sw_gctl1);
|
||||
es_w32_mask(0, LTQ_ES_SW_GCTL1_REG_RP_VAL(7), sw_gctl1);
|
||||
|
||||
/* Enable LAN port(s) */
|
||||
if (eth_port == 0)
|
||||
es_w32_mask(LTQ_ES_P0_CTL_REG_SPS, 0, p0_ctl);
|
||||
else
|
||||
es_w32_mask(LTQ_ES_P0_CTL_REG_SPS, 0, p1_ctl);
|
||||
/* Enable CPU Port (Forwarding State) */
|
||||
es_w32_mask(LTQ_ES_P0_CTL_REG_SPS, 0, p2_ctl);
|
||||
|
||||
if (phy_present)
|
||||
switchip_mdio_poll_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(switchip_init);
|
||||
|
||||
device_initcall(switchip_init);
|
||||
329
target/linux/lantiq/files/arch/mips/lantiq/xway/clk.c
Normal file
329
target/linux/lantiq/files/arch/mips/lantiq/xway/clk.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/time.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "../clk.h"
|
||||
|
||||
static unsigned int ltq_ram_clocks[] = {
|
||||
CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
|
||||
#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
|
||||
|
||||
#define BASIC_FREQUENCY_1 35328000
|
||||
#define BASIC_FREQUENCY_2 36000000
|
||||
#define BASIS_REQUENCY_USB 12000000
|
||||
|
||||
#define GET_BITS(x, msb, lsb) \
|
||||
(((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
|
||||
|
||||
/* legacy xway clock */
|
||||
#define LTQ_CGU_PLL0_CFG 0x0004
|
||||
#define LTQ_CGU_PLL1_CFG 0x0008
|
||||
#define LTQ_CGU_PLL2_CFG 0x000C
|
||||
#define LTQ_CGU_SYS 0x0010
|
||||
#define LTQ_CGU_UPDATE 0x0014
|
||||
#define LTQ_CGU_IF_CLK 0x0018
|
||||
#define LTQ_CGU_OSC_CON 0x001C
|
||||
#define LTQ_CGU_SMD 0x0020
|
||||
#define LTQ_CGU_CT1SR 0x0028
|
||||
#define LTQ_CGU_CT2SR 0x002C
|
||||
#define LTQ_CGU_PCMCR 0x0030
|
||||
#define LTQ_CGU_PCI_CR 0x0034
|
||||
#define LTQ_CGU_PD_PC 0x0038
|
||||
#define LTQ_CGU_FMR 0x003C
|
||||
|
||||
#define CGU_PLL0_PHASE_DIVIDER_ENABLE \
|
||||
(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
|
||||
#define CGU_PLL0_BYPASS \
|
||||
(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
|
||||
#define CGU_PLL0_CFG_DSMSEL \
|
||||
(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
|
||||
#define CGU_PLL0_CFG_FRAC_EN \
|
||||
(ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
|
||||
#define CGU_PLL1_SRC \
|
||||
(ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
|
||||
#define CGU_PLL2_PHASE_DIVIDER_ENABLE \
|
||||
(ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
|
||||
#define CGU_SYS_FPI_SEL (1 << 6)
|
||||
#define CGU_SYS_DDR_SEL 0x3
|
||||
#define CGU_PLL0_SRC (1 << 29)
|
||||
|
||||
#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
|
||||
#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
|
||||
#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
|
||||
#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
|
||||
#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
|
||||
|
||||
/* vr9 clock */
|
||||
#define LTQ_CGU_SYS_VR9 0x0c
|
||||
#define LTQ_CGU_IF_CLK_VR9 0x24
|
||||
|
||||
|
||||
static unsigned int ltq_get_pll0_fdiv(void);
|
||||
|
||||
static inline unsigned int get_input_clock(int pll)
|
||||
{
|
||||
switch (pll) {
|
||||
case 0:
|
||||
if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
|
||||
return BASIS_REQUENCY_USB;
|
||||
else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
|
||||
return BASIC_FREQUENCY_1;
|
||||
else
|
||||
return BASIC_FREQUENCY_2;
|
||||
case 1:
|
||||
if (CGU_PLL1_SRC)
|
||||
return BASIS_REQUENCY_USB;
|
||||
else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
|
||||
return BASIC_FREQUENCY_1;
|
||||
else
|
||||
return BASIC_FREQUENCY_2;
|
||||
case 2:
|
||||
switch (CGU_PLL2_SRC) {
|
||||
case 0:
|
||||
return ltq_get_pll0_fdiv();
|
||||
case 1:
|
||||
return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
|
||||
BASIC_FREQUENCY_1 :
|
||||
BASIC_FREQUENCY_2;
|
||||
case 2:
|
||||
return BASIS_REQUENCY_USB;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
|
||||
{
|
||||
u64 res, clock = get_input_clock(pll);
|
||||
|
||||
res = num * clock;
|
||||
do_div(res, den);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
|
||||
unsigned int K)
|
||||
{
|
||||
unsigned int num = ((N + 1) << 10) + K;
|
||||
unsigned int den = (M + 1) << 10;
|
||||
|
||||
return cal_dsm(pll, num, den);
|
||||
}
|
||||
|
||||
static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
|
||||
unsigned int K)
|
||||
{
|
||||
unsigned int num = ((N + 1) << 11) + K + 512;
|
||||
unsigned int den = (M + 1) << 11;
|
||||
|
||||
return cal_dsm(pll, num, den);
|
||||
}
|
||||
|
||||
static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
|
||||
unsigned int K)
|
||||
{
|
||||
unsigned int num = K >= 512 ?
|
||||
((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
|
||||
unsigned int den = (M + 1) << 12;
|
||||
|
||||
return cal_dsm(pll, num, den);
|
||||
}
|
||||
|
||||
static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
|
||||
unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
|
||||
{
|
||||
if (!dsmsel)
|
||||
return mash_dsm(pll, M, N, K);
|
||||
else if (!phase_div_en)
|
||||
return mash_dsm(pll, M, N, K);
|
||||
else
|
||||
return ssff_dsm_2(pll, M, N, K);
|
||||
}
|
||||
|
||||
static inline unsigned int ltq_get_pll0_fosc(void)
|
||||
{
|
||||
if (CGU_PLL0_BYPASS)
|
||||
return get_input_clock(0);
|
||||
else
|
||||
return !CGU_PLL0_CFG_FRAC_EN
|
||||
? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
|
||||
CGU_PLL0_CFG_DSMSEL,
|
||||
CGU_PLL0_PHASE_DIVIDER_ENABLE)
|
||||
: dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
|
||||
CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
|
||||
CGU_PLL0_PHASE_DIVIDER_ENABLE);
|
||||
}
|
||||
|
||||
static unsigned int ltq_get_pll0_fdiv(void)
|
||||
{
|
||||
unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
|
||||
|
||||
return (ltq_get_pll0_fosc() + (div >> 1)) / div;
|
||||
}
|
||||
|
||||
unsigned long ltq_danube_io_region_clock(void)
|
||||
{
|
||||
unsigned int ret = ltq_get_pll0_fosc();
|
||||
|
||||
switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0x3) {
|
||||
default:
|
||||
case 0:
|
||||
return (ret + 1) / 2;
|
||||
case 1:
|
||||
return (ret * 2 + 2) / 5;
|
||||
case 2:
|
||||
return (ret + 1) / 3;
|
||||
case 3:
|
||||
return (ret + 2) / 4;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long ltq_danube_fpi_bus_clock(int fpi)
|
||||
{
|
||||
unsigned long ret = ltq_danube_io_region_clock();
|
||||
|
||||
if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
|
||||
ret >>= 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned long ltq_danube_fpi_hz(void)
|
||||
{
|
||||
unsigned long ddr_clock = DDR_HZ;
|
||||
|
||||
if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
|
||||
return ddr_clock >> 1;
|
||||
return ddr_clock;
|
||||
}
|
||||
|
||||
unsigned long ltq_danube_cpu_hz(void)
|
||||
{
|
||||
switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
|
||||
case 0:
|
||||
return CLOCK_333M;
|
||||
case 4:
|
||||
return DDR_HZ;
|
||||
case 8:
|
||||
return DDR_HZ << 1;
|
||||
default:
|
||||
return DDR_HZ >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long ltq_ar9_sys_hz(void)
|
||||
{
|
||||
if (((ltq_cgu_r32(LTQ_CGU_SYS) >> 3) & 0x3) == 0x2)
|
||||
return CLOCK_393M;
|
||||
return CLOCK_333M;
|
||||
}
|
||||
|
||||
unsigned long ltq_ar9_fpi_hz(void)
|
||||
{
|
||||
unsigned long sys = ltq_ar9_sys_hz();
|
||||
|
||||
if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(0))
|
||||
return sys;
|
||||
return sys >> 1;
|
||||
}
|
||||
|
||||
unsigned long ltq_ar9_cpu_hz(void)
|
||||
{
|
||||
if (ltq_cgu_r32(LTQ_CGU_SYS) & BIT(2))
|
||||
return ltq_ar9_fpi_hz();
|
||||
else
|
||||
return ltq_ar9_sys_hz();
|
||||
}
|
||||
|
||||
unsigned long ltq_vr9_cpu_hz(void)
|
||||
{
|
||||
unsigned int cpu_sel;
|
||||
unsigned long clk;
|
||||
|
||||
cpu_sel = (ltq_cgu_r32(LTQ_CGU_SYS_VR9) >> 4) & 0xf;
|
||||
|
||||
switch (cpu_sel) {
|
||||
case 0:
|
||||
clk = CLOCK_600M;
|
||||
break;
|
||||
case 1:
|
||||
clk = CLOCK_500M;
|
||||
break;
|
||||
case 2:
|
||||
clk = CLOCK_393M;
|
||||
break;
|
||||
case 3:
|
||||
clk = CLOCK_333M;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
clk = CLOCK_196_608M;
|
||||
break;
|
||||
case 7:
|
||||
clk = CLOCK_167M;
|
||||
break;
|
||||
case 4:
|
||||
case 8:
|
||||
case 9:
|
||||
clk = CLOCK_125M;
|
||||
break;
|
||||
default:
|
||||
clk = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
unsigned long ltq_vr9_fpi_hz(void)
|
||||
{
|
||||
unsigned int ocp_sel, cpu_clk;
|
||||
unsigned long clk;
|
||||
|
||||
cpu_clk = ltq_vr9_cpu_hz();
|
||||
ocp_sel = ltq_cgu_r32(LTQ_CGU_SYS_VR9) & 0x3;
|
||||
|
||||
switch (ocp_sel) {
|
||||
case 0:
|
||||
/* OCP ratio 1 */
|
||||
clk = cpu_clk;
|
||||
break;
|
||||
case 2:
|
||||
/* OCP ratio 2 */
|
||||
clk = cpu_clk / 2;
|
||||
break;
|
||||
case 3:
|
||||
/* OCP ratio 2.5 */
|
||||
clk = (cpu_clk * 2) / 5;
|
||||
break;
|
||||
case 4:
|
||||
/* OCP ratio 3 */
|
||||
clk = cpu_clk / 3;
|
||||
break;
|
||||
default:
|
||||
clk = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
unsigned long ltq_vr9_fpi_bus_clock(int fpi)
|
||||
{
|
||||
return ltq_vr9_fpi_hz();
|
||||
}
|
||||
45
target/linux/lantiq/files/arch/mips/lantiq/xway/dev-ifxhcd.c
Normal file
45
target/linux/lantiq/files/arch/mips/lantiq/xway/dev-ifxhcd.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <lantiq_irq.h>
|
||||
#include <lantiq_platform.h>
|
||||
|
||||
static u64 dmamask = (u32)0x1fffffff;
|
||||
|
||||
static struct platform_device platform_dev = {
|
||||
.name = "ifxusb_hcd",
|
||||
.dev.dma_mask = &dmamask,
|
||||
};
|
||||
|
||||
int __init
|
||||
xway_register_hcd(int *pins)
|
||||
{
|
||||
platform_dev.dev.platform_data = pins;
|
||||
return platform_device_register(&platform_dev);
|
||||
}
|
||||
17
target/linux/lantiq/files/arch/mips/lantiq/xway/dev-ifxhcd.h
Normal file
17
target/linux/lantiq/files/arch/mips/lantiq/xway/dev-ifxhcd.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#ifndef _LTQ_DEV_HCD_H__
|
||||
#define _LTQ_DEV_HCD_H__
|
||||
|
||||
#include <lantiq_platform.h>
|
||||
|
||||
extern void __init xway_register_hcd(int *pin);
|
||||
|
||||
#endif
|
||||
176
target/linux/lantiq/files/arch/mips/lantiq/xway/gptu.c
Normal file
176
target/linux/lantiq/files/arch/mips/lantiq/xway/gptu.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/reboot.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include "../clk.h"
|
||||
|
||||
#include "../devices.h"
|
||||
|
||||
#define ltq_gptu_w32(x, y) ltq_w32((x), ltq_gptu_membase + (y))
|
||||
#define ltq_gptu_r32(x) ltq_r32(ltq_gptu_membase + (x))
|
||||
|
||||
|
||||
/* the magic ID byte of the core */
|
||||
#define GPTU_MAGIC 0x59
|
||||
/* clock control register */
|
||||
#define GPTU_CLC 0x00
|
||||
/* id register */
|
||||
#define GPTU_ID 0x08
|
||||
/* interrupt node enable */
|
||||
#define GPTU_IRNEN 0xf4
|
||||
/* interrupt control register */
|
||||
#define GPTU_IRCR 0xf8
|
||||
/* interrupt capture register */
|
||||
#define GPTU_IRNCR 0xfc
|
||||
/* there are 3 identical blocks of 2 timers. calculate register offsets */
|
||||
#define GPTU_SHIFT(x) (x % 2 ? 4 : 0)
|
||||
#define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10)
|
||||
/* timer control register */
|
||||
#define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00)
|
||||
/* timer auto reload register */
|
||||
#define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08)
|
||||
/* timer manual reload register */
|
||||
#define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10)
|
||||
/* timer count register */
|
||||
#define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18)
|
||||
|
||||
/* GPTU_CON(x) */
|
||||
#define CON_CNT BIT(2)
|
||||
#define CON_EDGE_FALL BIT(7)
|
||||
#define CON_SYNC BIT(8)
|
||||
#define CON_CLK_INT BIT(10)
|
||||
|
||||
/* GPTU_RUN(x) */
|
||||
#define RUN_SEN BIT(0)
|
||||
#define RUN_RL BIT(2)
|
||||
|
||||
/* set clock to runmode */
|
||||
#define CLC_RMC BIT(8)
|
||||
/* bring core out of suspend */
|
||||
#define CLC_SUSPEND BIT(4)
|
||||
/* the disable bit */
|
||||
#define CLC_DISABLE BIT(0)
|
||||
|
||||
#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22)
|
||||
|
||||
enum gptu_timer {
|
||||
TIMER1A = 0,
|
||||
TIMER1B,
|
||||
TIMER2A,
|
||||
TIMER2B,
|
||||
TIMER3A,
|
||||
TIMER3B
|
||||
};
|
||||
|
||||
static struct resource ltq_gptu_resource =
|
||||
MEM_RES("GPTU", LTQ_GPTU_BASE_ADDR, LTQ_GPTU_SIZE);
|
||||
|
||||
static void __iomem *ltq_gptu_membase;
|
||||
|
||||
static irqreturn_t timer_irq_handler(int irq, void *priv)
|
||||
{
|
||||
int timer = irq - TIMER_INTERRUPT;
|
||||
ltq_gptu_w32(1 << timer, GPTU_IRNCR);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void gptu_hwinit(void)
|
||||
{
|
||||
struct clk *clk = clk_get_sys("ltq_gptu", NULL);
|
||||
clk_enable(clk);
|
||||
ltq_gptu_w32(0x00, GPTU_IRNEN);
|
||||
ltq_gptu_w32(0xff, GPTU_IRNCR);
|
||||
ltq_gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC);
|
||||
}
|
||||
|
||||
static void gptu_hwexit(void)
|
||||
{
|
||||
ltq_gptu_w32(0x00, GPTU_IRNEN);
|
||||
ltq_gptu_w32(0xff, GPTU_IRNCR);
|
||||
ltq_gptu_w32(CLC_DISABLE, GPTU_CLC);
|
||||
}
|
||||
|
||||
static int ltq_gptu_enable(struct clk *clk)
|
||||
{
|
||||
int ret = request_irq(TIMER_INTERRUPT + clk->bits, timer_irq_handler,
|
||||
IRQF_TIMER, "timer", NULL);
|
||||
if (ret) {
|
||||
pr_err("gptu: failed to request irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ltq_gptu_w32(CON_CNT | CON_EDGE_FALL | CON_SYNC | CON_CLK_INT,
|
||||
GPTU_CON(clk->bits));
|
||||
ltq_gptu_w32(1, GPTU_RLD(clk->bits));
|
||||
ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) | clk->bits, GPTU_IRNEN);
|
||||
ltq_gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltq_gptu_disable(struct clk *clk)
|
||||
{
|
||||
ltq_gptu_w32(0, GPTU_RUN(clk->bits));
|
||||
ltq_gptu_w32(0, GPTU_CON(clk->bits));
|
||||
ltq_gptu_w32(0, GPTU_RLD(clk->bits));
|
||||
ltq_gptu_w32(ltq_gptu_r32(GPTU_IRNEN) & ~clk->bits, GPTU_IRNEN);
|
||||
free_irq(TIMER_INTERRUPT + clk->bits, NULL);
|
||||
}
|
||||
|
||||
static inline void clkdev_add_gptu(const char *con, unsigned int timer)
|
||||
{
|
||||
struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
|
||||
|
||||
clk->cl.dev_id = "ltq_gptu";
|
||||
clk->cl.con_id = con;
|
||||
clk->cl.clk = clk;
|
||||
clk->enable = ltq_gptu_enable;
|
||||
clk->disable = ltq_gptu_disable;
|
||||
clk->bits = timer;
|
||||
clkdev_add(&clk->cl);
|
||||
}
|
||||
|
||||
static int __init gptu_setup(void)
|
||||
{
|
||||
/* remap gptu register range */
|
||||
ltq_gptu_membase = ltq_remap_resource(<q_gptu_resource);
|
||||
if (!ltq_gptu_membase)
|
||||
panic("Failed to remap gptu memory");
|
||||
|
||||
/* power up the core */
|
||||
gptu_hwinit();
|
||||
|
||||
/* the gptu has a ID register */
|
||||
if (((ltq_gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) {
|
||||
pr_err("gptu: failed to find magic\n");
|
||||
gptu_hwexit();
|
||||
return -ENAVAIL;
|
||||
}
|
||||
|
||||
/* register the clocks */
|
||||
clkdev_add_gptu("timer1a", TIMER1A);
|
||||
clkdev_add_gptu("timer1b", TIMER1B);
|
||||
clkdev_add_gptu("timer2a", TIMER2A);
|
||||
clkdev_add_gptu("timer2b", TIMER2B);
|
||||
clkdev_add_gptu("timer3a", TIMER3A);
|
||||
clkdev_add_gptu("timer3b", TIMER3B);
|
||||
|
||||
pr_info("gptu: 6 timers loaded\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(gptu_setup);
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <lantiq.h>
|
||||
|
||||
#include "../machtypes.h"
|
||||
#include "devices.h"
|
||||
|
||||
static struct mtd_partition easy50601_partitions[] = {
|
||||
{
|
||||
.name = "uboot",
|
||||
.offset = 0x0,
|
||||
.size = 0x10000,
|
||||
},
|
||||
{
|
||||
.name = "uboot_env",
|
||||
.offset = 0x10000,
|
||||
.size = 0x10000,
|
||||
},
|
||||
{
|
||||
.name = "linux",
|
||||
.offset = 0x20000,
|
||||
.size = 0x3d0000,
|
||||
},
|
||||
};
|
||||
|
||||
static struct physmap_flash_data easy50601_flash_data = {
|
||||
.nr_parts = ARRAY_SIZE(easy50601_partitions),
|
||||
.parts = easy50601_partitions,
|
||||
};
|
||||
|
||||
static struct ltq_eth_data ltq_eth_data = {
|
||||
.mii_mode = -1, /* use EPHY */
|
||||
};
|
||||
|
||||
static void __init
|
||||
easy50601_init(void)
|
||||
{
|
||||
ltq_register_nor(&easy50601_flash_data);
|
||||
ltq_register_etop(<q_eth_data);
|
||||
}
|
||||
|
||||
MIPS_MACHINE(LTQ_MACH_EASY50601,
|
||||
"EASY50601",
|
||||
"EASY50601 Eval Board",
|
||||
easy50601_init);
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <irq.h>
|
||||
|
||||
#include "../machtypes.h"
|
||||
#include "devices.h"
|
||||
|
||||
static struct mtd_partition easy50712_partitions[] = {
|
||||
{
|
||||
.name = "uboot",
|
||||
.offset = 0x0,
|
||||
.size = 0x10000,
|
||||
},
|
||||
{
|
||||
.name = "uboot_env",
|
||||
.offset = 0x10000,
|
||||
.size = 0x10000,
|
||||
},
|
||||
{
|
||||
.name = "linux",
|
||||
.offset = 0x20000,
|
||||
.size = 0x3d0000,
|
||||
},
|
||||
};
|
||||
|
||||
static struct physmap_flash_data easy50712_flash_data = {
|
||||
.nr_parts = ARRAY_SIZE(easy50712_partitions),
|
||||
.parts = easy50712_partitions,
|
||||
};
|
||||
|
||||
static struct ltq_pci_data ltq_pci_data = {
|
||||
.clock = PCI_CLOCK_INT,
|
||||
.gpio = PCI_GNT1 | PCI_REQ1,
|
||||
.irq = {
|
||||
[14] = INT_NUM_IM0_IRL0 + 22,
|
||||
},
|
||||
};
|
||||
|
||||
static struct ltq_eth_data ltq_eth_data = {
|
||||
.mii_mode = PHY_INTERFACE_MODE_MII,
|
||||
};
|
||||
|
||||
static void __init
|
||||
easy50712_init(void)
|
||||
{
|
||||
ltq_register_gpio_stp();
|
||||
ltq_register_nor(&easy50712_flash_data);
|
||||
ltq_register_pci(<q_pci_data);
|
||||
ltq_register_etop(<q_eth_data);
|
||||
ltq_register_tapi();
|
||||
}
|
||||
|
||||
MIPS_MACHINE(LTQ_MACH_EASY50712,
|
||||
"EASY50712",
|
||||
"EASY50712 Eval Board",
|
||||
easy50712_init);
|
||||
216
target/linux/lantiq/files/arch/mips/lantiq/xway/nand.c
Normal file
216
target/linux/lantiq/files/arch/mips/lantiq/xway/nand.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <lantiq_irq.h>
|
||||
#include <lantiq_platform.h>
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
/* nand registers */
|
||||
#define LTQ_EBU_NAND_WAIT 0xB4
|
||||
#define LTQ_EBU_NAND_ECC0 0xB8
|
||||
#define LTQ_EBU_NAND_ECC_AC 0xBC
|
||||
#define LTQ_EBU_NAND_CON 0xB0
|
||||
#define LTQ_EBU_ADDSEL1 0x24
|
||||
|
||||
/* gpio definitions */
|
||||
#define PIN_ALE 13
|
||||
#define PIN_CLE 24
|
||||
#define PIN_CS1 23
|
||||
#define PIN_RDY 48 /* NFLASH_READY */
|
||||
#define PIN_RD 49 /* NFLASH_READ_N */
|
||||
|
||||
#define NAND_CMD_ALE (1 << 2)
|
||||
#define NAND_CMD_CLE (1 << 3)
|
||||
#define NAND_CMD_CS (1 << 4)
|
||||
#define NAND_WRITE_CMD_RESET 0xff
|
||||
#define NAND_WRITE_CMD (NAND_CMD_CS | NAND_CMD_CLE)
|
||||
#define NAND_WRITE_ADDR (NAND_CMD_CS | NAND_CMD_ALE)
|
||||
#define NAND_WRITE_DATA (NAND_CMD_CS)
|
||||
#define NAND_READ_DATA (NAND_CMD_CS)
|
||||
#define NAND_WAIT_WR_C (1 << 3)
|
||||
#define NAND_WAIT_RD (0x1)
|
||||
|
||||
#define ADDSEL1_MASK(x) (x << 4)
|
||||
#define ADDSEL1_REGEN 1
|
||||
#define BUSCON1_SETUP (1 << 22)
|
||||
#define BUSCON1_BCGEN_RES (0x3 << 12)
|
||||
#define BUSCON1_WAITWRC2 (2 << 8)
|
||||
#define BUSCON1_WAITRDC2 (2 << 6)
|
||||
#define BUSCON1_HOLDC1 (1 << 4)
|
||||
#define BUSCON1_RECOVC1 (1 << 2)
|
||||
#define BUSCON1_CMULT4 1
|
||||
#define NAND_CON_NANDM 1
|
||||
#define NAND_CON_CSMUX (1 << 1)
|
||||
#define NAND_CON_CS_P (1 << 4)
|
||||
#define NAND_CON_SE_P (1 << 5)
|
||||
#define NAND_CON_WP_P (1 << 6)
|
||||
#define NAND_CON_PRE_P (1 << 7)
|
||||
#define NAND_CON_IN_CS0 0
|
||||
#define NAND_CON_OUT_CS0 0
|
||||
#define NAND_CON_IN_CS1 (1 << 8)
|
||||
#define NAND_CON_OUT_CS1 (1 << 10)
|
||||
#define NAND_CON_CE (1 << 20)
|
||||
|
||||
#define NAND_BASE_ADDRESS (KSEG1 | 0x14000000)
|
||||
|
||||
static const char *part_probes[] = { "cmdlinepart", NULL };
|
||||
|
||||
static void xway_select_chip(struct mtd_info *mtd, int chip)
|
||||
{
|
||||
switch (chip) {
|
||||
case -1:
|
||||
ltq_ebu_w32_mask(NAND_CON_CE, 0, LTQ_EBU_NAND_CON);
|
||||
ltq_ebu_w32_mask(NAND_CON_NANDM, 0, LTQ_EBU_NAND_CON);
|
||||
break;
|
||||
case 0:
|
||||
ltq_ebu_w32_mask(0, NAND_CON_NANDM, LTQ_EBU_NAND_CON);
|
||||
ltq_ebu_w32_mask(0, NAND_CON_CE, LTQ_EBU_NAND_CON);
|
||||
/* reset the nand chip */
|
||||
while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
|
||||
;
|
||||
ltq_w32(NAND_WRITE_CMD_RESET,
|
||||
((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD)));
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
static void xway_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
if (ctrl & NAND_CLE)
|
||||
this->IO_ADDR_W = (void __iomem *)
|
||||
(NAND_BASE_ADDRESS | NAND_WRITE_CMD);
|
||||
else if (ctrl & NAND_ALE)
|
||||
this->IO_ADDR_W = (void __iomem *)
|
||||
(NAND_BASE_ADDRESS | NAND_WRITE_ADDR);
|
||||
}
|
||||
|
||||
if (data != NAND_CMD_NONE) {
|
||||
*(volatile u8*) ((u32) this->IO_ADDR_W) = data;
|
||||
while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static int xway_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
return ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_RD;
|
||||
}
|
||||
|
||||
void nand_write(unsigned int addr, unsigned int val)
|
||||
{
|
||||
ltq_w32(val, ((u32 *) (NAND_BASE_ADDRESS | addr)));
|
||||
while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
unsigned char xway_read_byte(struct mtd_info *mtd)
|
||||
{
|
||||
return ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA)));
|
||||
}
|
||||
|
||||
static void xway_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
unsigned char res8 = ltq_r8((void __iomem *)(NAND_BASE_ADDRESS | (NAND_READ_DATA)));
|
||||
buf[i] = res8;
|
||||
}
|
||||
}
|
||||
|
||||
static void xway_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
ltq_w8(buf[i], ((u32*)(NAND_BASE_ADDRESS | (NAND_WRITE_DATA))));
|
||||
while((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
int xway_probe(struct platform_device *pdev)
|
||||
{
|
||||
/* might need this later ?
|
||||
ltq_gpio_request(PIN_CS1, 2, 1, "NAND_CS1");
|
||||
*/
|
||||
ltq_gpio_request(&pdev->dev, PIN_CLE, 2, 1, "NAND_CLE");
|
||||
ltq_gpio_request(&pdev->dev, PIN_ALE, 2, 1, "NAND_ALE");
|
||||
if (ltq_is_ar9() || ltq_is_vr9()) {
|
||||
ltq_gpio_request(&pdev->dev, PIN_RDY, 2, 0, "NAND_BSY");
|
||||
ltq_gpio_request(&pdev->dev, PIN_RD, 2, 1, "NAND_RD");
|
||||
}
|
||||
|
||||
ltq_ebu_w32((NAND_BASE_ADDRESS & 0x1fffff00)
|
||||
| ADDSEL1_MASK(3) | ADDSEL1_REGEN, LTQ_EBU_ADDSEL1);
|
||||
|
||||
ltq_ebu_w32(BUSCON1_SETUP | BUSCON1_BCGEN_RES | BUSCON1_WAITWRC2
|
||||
| BUSCON1_WAITRDC2 | BUSCON1_HOLDC1 | BUSCON1_RECOVC1
|
||||
| BUSCON1_CMULT4, LTQ_EBU_BUSCON1);
|
||||
|
||||
ltq_ebu_w32(NAND_CON_NANDM | NAND_CON_CSMUX | NAND_CON_CS_P
|
||||
| NAND_CON_SE_P | NAND_CON_WP_P | NAND_CON_PRE_P
|
||||
| NAND_CON_IN_CS0 | NAND_CON_OUT_CS0, LTQ_EBU_NAND_CON);
|
||||
|
||||
ltq_w32(NAND_WRITE_CMD_RESET,
|
||||
((u32 *) (NAND_BASE_ADDRESS | NAND_WRITE_CMD)));
|
||||
while ((ltq_ebu_r32(LTQ_EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_nand_data falcon_flash_nand_data = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.chip_delay = 30,
|
||||
.part_probe_types = part_probes,
|
||||
},
|
||||
.ctrl = {
|
||||
.probe = xway_probe,
|
||||
.cmd_ctrl = xway_cmd_ctrl,
|
||||
.dev_ready = xway_dev_ready,
|
||||
.select_chip = xway_select_chip,
|
||||
.read_byte = xway_read_byte,
|
||||
.read_buf = xway_read_buf,
|
||||
.write_buf = xway_write_buf,
|
||||
}
|
||||
};
|
||||
|
||||
static struct resource ltq_nand_res =
|
||||
MEM_RES("nand", 0x14000000, 0x7ffffff);
|
||||
|
||||
static struct platform_device ltq_flash_nand = {
|
||||
.name = "gen_nand",
|
||||
.id = -1,
|
||||
.num_resources = 1,
|
||||
.resource = <q_nand_res,
|
||||
.dev = {
|
||||
.platform_data = &falcon_flash_nand_data,
|
||||
},
|
||||
};
|
||||
|
||||
void __init xway_register_nand(struct mtd_partition *parts, int count)
|
||||
{
|
||||
falcon_flash_nand_data.chip.partitions = parts;
|
||||
falcon_flash_nand_data.chip.nr_partitions = count;
|
||||
platform_device_register(<q_flash_nand);
|
||||
}
|
||||
110
target/linux/lantiq/files/arch/mips/lantiq/xway/prom.c
Normal file
110
target/linux/lantiq/files/arch/mips/lantiq/xway/prom.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/clk.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "../prom.h"
|
||||
#include "devices.h"
|
||||
|
||||
#define SOC_DANUBE "Danube"
|
||||
#define SOC_TWINPASS "Twinpass"
|
||||
#define SOC_AMAZON_SE "Amazon_SE"
|
||||
#define SOC_AR9 "AR9"
|
||||
#define SOC_GR9 "GR9"
|
||||
#define SOC_VR9 "VR9"
|
||||
|
||||
#define PART_SHIFT 12
|
||||
#define PART_MASK 0x0FFFFFFF
|
||||
#define REV_SHIFT 28
|
||||
#define REV_MASK 0xF0000000
|
||||
|
||||
|
||||
void __init ltq_soc_detect(struct ltq_soc_info *i)
|
||||
{
|
||||
i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
|
||||
i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
|
||||
sprintf(i->rev_type, "1.%d", i->rev);
|
||||
switch (i->partnum) {
|
||||
case SOC_ID_DANUBE1:
|
||||
case SOC_ID_DANUBE2:
|
||||
i->name = SOC_DANUBE;
|
||||
i->type = SOC_TYPE_DANUBE;
|
||||
break;
|
||||
|
||||
case SOC_ID_TWINPASS:
|
||||
i->name = SOC_TWINPASS;
|
||||
i->type = SOC_TYPE_DANUBE;
|
||||
break;
|
||||
|
||||
case SOC_ID_ARX188:
|
||||
case SOC_ID_ARX168_1:
|
||||
case SOC_ID_ARX168_2:
|
||||
case SOC_ID_ARX182:
|
||||
i->name = SOC_AR9;
|
||||
i->type = SOC_TYPE_AR9;
|
||||
break;
|
||||
|
||||
case SOC_ID_GRX188:
|
||||
case SOC_ID_GRX168:
|
||||
i->name = SOC_GR9;
|
||||
i->type = SOC_TYPE_AR9;
|
||||
break;
|
||||
|
||||
case SOC_ID_AMAZON_SE_1:
|
||||
case SOC_ID_AMAZON_SE_2:
|
||||
i->name = SOC_AMAZON_SE;
|
||||
i->type = SOC_TYPE_AMAZON_SE;
|
||||
#ifdef CONFIG_PCI
|
||||
panic("ase is only supported for non pci kernels");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SOC_ID_VRX282:
|
||||
case SOC_ID_VRX268:
|
||||
case SOC_ID_VRX288:
|
||||
i->name = SOC_VR9;
|
||||
i->type = SOC_TYPE_VR9_1;
|
||||
break;
|
||||
|
||||
case SOC_ID_GRX268:
|
||||
case SOC_ID_GRX288:
|
||||
i->name = SOC_GR9;
|
||||
i->type = SOC_TYPE_VR9_1;
|
||||
break;
|
||||
|
||||
case SOC_ID_VRX268_2:
|
||||
case SOC_ID_VRX288_2:
|
||||
i->name = SOC_VR9;
|
||||
i->type = SOC_TYPE_VR9_2;
|
||||
break;
|
||||
|
||||
case SOC_ID_GRX282_2:
|
||||
case SOC_ID_GRX288_2:
|
||||
i->name = SOC_GR9;
|
||||
i->type = SOC_TYPE_VR9_2;
|
||||
|
||||
default:
|
||||
unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void __init ltq_soc_setup(void)
|
||||
{
|
||||
if (ltq_is_ase())
|
||||
ltq_register_ase_asc();
|
||||
else
|
||||
ltq_register_asc(1);
|
||||
ltq_register_gpio();
|
||||
ltq_register_wdt();
|
||||
}
|
||||
283
target/linux/lantiq/files/arch/mips/lantiq/xway/sysctrl.c
Normal file
283
target/linux/lantiq/files/arch/mips/lantiq/xway/sysctrl.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2011 John Crispin <blogic@openwrt.org>
|
||||
*/
|
||||
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
#include "../clk.h"
|
||||
#include "../devices.h"
|
||||
|
||||
/* clock control register */
|
||||
#define CGU_IFCCR 0x0018
|
||||
/* system clock register */
|
||||
#define CGU_SYS 0x0010
|
||||
/* pci control register */
|
||||
#define CGU_PCICR 0x0034
|
||||
/* ephy configuration register */
|
||||
#define CGU_EPHY 0x10
|
||||
/* power control register */
|
||||
#define PMU_PWDCR 0x1C
|
||||
/* power status register */
|
||||
#define PMU_PWDSR 0x20
|
||||
/* power control register */
|
||||
#define PMU_PWDCR1 0x24
|
||||
/* power status register */
|
||||
#define PMU_PWDSR1 0x28
|
||||
/* power control register */
|
||||
#define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR))
|
||||
/* power status register */
|
||||
#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR))
|
||||
|
||||
/* PMU - power management unit */
|
||||
#define PMU_USB0_P BIT(0)
|
||||
#define PMU_PCI BIT(4)
|
||||
#define PMU_DMA BIT(5)
|
||||
#define PMU_USB0 BIT(6)
|
||||
#define PMU_EPHY BIT(7) /* ase */
|
||||
#define PMU_SPI BIT(8)
|
||||
#define PMU_DFE BIT(9)
|
||||
#define PMU_EBU BIT(10)
|
||||
#define PMU_STP BIT(11)
|
||||
#define PMU_GPT BIT(12)
|
||||
#define PMU_PPE BIT(13)
|
||||
#define PMU_AHBS BIT(13) /* vr9 */
|
||||
#define PMU_FPI BIT(14)
|
||||
#define PMU_AHBM BIT(15)
|
||||
#define PMU_PPE_QSB BIT(18)
|
||||
#define PMU_PPE_SLL01 BIT(19)
|
||||
#define PMU_PPE_TC BIT(21)
|
||||
#define PMU_PPE_EMA BIT(22)
|
||||
#define PMU_PPE_DPLUM BIT(23)
|
||||
#define PMU_PPE_DPLUS BIT(24)
|
||||
#define PMU_USB1_P BIT(26)
|
||||
#define PMU_USB1 BIT(27)
|
||||
#define PMU_SWITCH BIT(28)
|
||||
#define PMU_PPE_TOP BIT(29)
|
||||
#define PMU_GPHY BIT(30)
|
||||
#define PMU_PCIE_CLK BIT(31)
|
||||
|
||||
#define PMU1_PCIE_PHY BIT(0)
|
||||
#define PMU1_PCIE_CTL BIT(1)
|
||||
#define PMU1_PCIE_PDI BIT(4)
|
||||
#define PMU1_PCIE_MSI BIT(5)
|
||||
|
||||
#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
|
||||
#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
|
||||
|
||||
static struct resource ltq_cgu_resource =
|
||||
MEM_RES("cgu", LTQ_CGU_BASE_ADDR, LTQ_CGU_SIZE);
|
||||
|
||||
static struct resource ltq_pmu_resource =
|
||||
MEM_RES("pmu", LTQ_PMU_BASE_ADDR, LTQ_PMU_SIZE);
|
||||
|
||||
static struct resource ltq_ebu_resource =
|
||||
MEM_RES("ebu", LTQ_EBU_BASE_ADDR, LTQ_EBU_SIZE);
|
||||
|
||||
void __iomem *ltq_cgu_membase;
|
||||
void __iomem *ltq_ebu_membase;
|
||||
static void __iomem *ltq_pmu_membase;
|
||||
|
||||
static int ltq_cgu_enable(struct clk *clk)
|
||||
{
|
||||
ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | clk->bits, CGU_IFCCR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltq_cgu_disable(struct clk *clk)
|
||||
{
|
||||
ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~clk->bits, CGU_IFCCR);
|
||||
}
|
||||
|
||||
static int ltq_pmu_enable(struct clk *clk)
|
||||
{
|
||||
int err = 1000000;
|
||||
|
||||
ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) & ~clk->bits,
|
||||
PWDCR(clk->module));
|
||||
do {} while (--err && (ltq_pmu_r32(PWDSR(clk->module)) & clk->bits));
|
||||
|
||||
if (!err)
|
||||
panic("activating PMU module failed!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltq_pmu_disable(struct clk *clk)
|
||||
{
|
||||
ltq_pmu_w32(ltq_pmu_r32(PWDCR(clk->module)) | clk->bits,
|
||||
PWDCR(clk->module));
|
||||
}
|
||||
|
||||
static int ltq_pci_enable(struct clk *clk)
|
||||
{
|
||||
unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR);
|
||||
/* set clock bus speed */
|
||||
if (ltq_is_ar9()) {
|
||||
ifccr &= ~0x1f00000;
|
||||
if (clk->rate == CLOCK_33M)
|
||||
ifccr |= 0xe00000;
|
||||
else
|
||||
ifccr |= 0x700000; /* 62.5M */
|
||||
} else {
|
||||
ifccr &= ~0xf00000;
|
||||
if (clk->rate == CLOCK_33M)
|
||||
ifccr |= 0x800000;
|
||||
else
|
||||
ifccr |= 0x400000; /* 62.5M */
|
||||
}
|
||||
ltq_cgu_w32(ifccr, CGU_IFCCR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltq_pci_ext_enable(struct clk *clk)
|
||||
{
|
||||
/* enable external pci clock */
|
||||
ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~(1 << 16),
|
||||
CGU_IFCCR);
|
||||
ltq_cgu_w32((1 << 30), CGU_PCICR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ltq_pci_ext_disable(struct clk *clk)
|
||||
{
|
||||
/* disable external pci clock (internal) */
|
||||
ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16),
|
||||
CGU_IFCCR);
|
||||
ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR);
|
||||
}
|
||||
|
||||
/* manage the clock gates via PMU */
|
||||
static inline void clkdev_add_pmu(const char *dev, const char *con,
|
||||
unsigned int module, unsigned int bits)
|
||||
{
|
||||
struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
|
||||
|
||||
clk->cl.dev_id = dev;
|
||||
clk->cl.con_id = con;
|
||||
clk->cl.clk = clk;
|
||||
clk->enable = ltq_pmu_enable;
|
||||
clk->disable = ltq_pmu_disable;
|
||||
clk->module = module;
|
||||
clk->bits = bits;
|
||||
clkdev_add(&clk->cl);
|
||||
}
|
||||
|
||||
/* manage the clock generator */
|
||||
static inline void clkdev_add_cgu(const char *dev, const char *con,
|
||||
unsigned int bits)
|
||||
{
|
||||
struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
|
||||
|
||||
clk->cl.dev_id = dev;
|
||||
clk->cl.con_id = con;
|
||||
clk->cl.clk = clk;
|
||||
clk->enable = ltq_cgu_enable;
|
||||
clk->disable = ltq_cgu_disable;
|
||||
clk->bits = bits;
|
||||
clkdev_add(&clk->cl);
|
||||
}
|
||||
|
||||
/* pci needs its own enable function */
|
||||
static inline void clkdev_add_pci(void)
|
||||
{
|
||||
struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
|
||||
struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL);
|
||||
|
||||
/* main pci clock */
|
||||
clk->cl.dev_id = "ltq_pci";
|
||||
clk->cl.con_id = NULL;
|
||||
clk->cl.clk = clk;
|
||||
clk->rate = CLOCK_33M;
|
||||
clk->enable = ltq_pci_enable;
|
||||
clk->disable = ltq_pmu_disable;
|
||||
clk->module = 0;
|
||||
clk->bits = PMU_PCI;
|
||||
clkdev_add(&clk->cl);
|
||||
|
||||
/* use internal/external bus clock */
|
||||
clk_ext->cl.dev_id = "ltq_pci";
|
||||
clk_ext->cl.con_id = "external";
|
||||
clk_ext->cl.clk = clk_ext;
|
||||
clk_ext->enable = ltq_pci_ext_enable;
|
||||
clk_ext->disable = ltq_pci_ext_disable;
|
||||
clkdev_add(&clk_ext->cl);
|
||||
|
||||
}
|
||||
|
||||
void __init ltq_soc_init(void)
|
||||
{
|
||||
ltq_pmu_membase = ltq_remap_resource(<q_pmu_resource);
|
||||
if (!ltq_pmu_membase)
|
||||
panic("Failed to remap pmu memory\n");
|
||||
|
||||
ltq_cgu_membase = ltq_remap_resource(<q_cgu_resource);
|
||||
if (!ltq_cgu_membase)
|
||||
panic("Failed to remap cgu memory\n");
|
||||
|
||||
ltq_ebu_membase = ltq_remap_resource(<q_ebu_resource);
|
||||
if (!ltq_ebu_membase)
|
||||
panic("Failed to remap ebu memory\n");
|
||||
|
||||
/* make sure to unprotect the memory region where flash is located */
|
||||
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
|
||||
|
||||
/* add our clocks */
|
||||
clkdev_add_pmu("ltq_fpi", NULL, 0, PMU_FPI);
|
||||
clkdev_add_pmu("ltq_dma", NULL, 0, PMU_DMA);
|
||||
clkdev_add_pmu("ltq_stp", NULL, 0, PMU_STP);
|
||||
clkdev_add_pmu("ltq_spi.0", NULL, 0, PMU_SPI);
|
||||
clkdev_add_pmu("ltq_gptu", NULL, 0, PMU_GPT);
|
||||
clkdev_add_pmu("ltq_ebu", NULL, 0, PMU_EBU);
|
||||
if (!ltq_is_vr9())
|
||||
clkdev_add_pmu("ltq_etop", NULL, 0, PMU_PPE);
|
||||
if (!ltq_is_ase())
|
||||
clkdev_add_pci();
|
||||
if (ltq_is_ase()) {
|
||||
if (ltq_cgu_r32(CGU_SYS) & (1 << 5))
|
||||
clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M);
|
||||
else
|
||||
clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M);
|
||||
clkdev_add_cgu("ltq_etop", "ephycgu", CGU_EPHY),
|
||||
clkdev_add_pmu("ltq_etop", "ephy", 0, PMU_EPHY);
|
||||
clkdev_add_pmu("ltq_dsl", NULL, 0,
|
||||
PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
|
||||
PMU_AHBS | PMU_DFE);
|
||||
} else if (ltq_is_vr9()) {
|
||||
clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(),
|
||||
ltq_vr9_fpi_hz());
|
||||
clkdev_add_pmu("ltq_pcie", "phy", 1, PMU1_PCIE_PHY);
|
||||
clkdev_add_pmu("ltq_pcie", "bus", 0, PMU_PCIE_CLK);
|
||||
clkdev_add_pmu("ltq_pcie", "msi", 1, PMU1_PCIE_MSI);
|
||||
clkdev_add_pmu("ltq_pcie", "pdi", 1, PMU1_PCIE_PDI);
|
||||
clkdev_add_pmu("ltq_pcie", "ctl", 1, PMU1_PCIE_CTL);
|
||||
clkdev_add_pmu("ltq_pcie", "ahb", 0, PMU_AHBM | PMU_AHBS);
|
||||
clkdev_add_pmu("usb0", NULL, 0, PMU_USB0 | PMU_USB0_P);
|
||||
clkdev_add_pmu("usb1", NULL, 0, PMU_USB1 | PMU_USB1_P);
|
||||
clkdev_add_pmu("ltq_vrx200", NULL, 0,
|
||||
PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
|
||||
PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
|
||||
PMU_PPE_QSB);
|
||||
clkdev_add_pmu("ltq_dsl", NULL, 0, PMU_DFE | PMU_AHBS);
|
||||
} else if (ltq_is_ar9()) {
|
||||
clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
|
||||
ltq_ar9_fpi_hz());
|
||||
clkdev_add_pmu("ltq_etop", "switch", 0, PMU_SWITCH);
|
||||
clkdev_add_pmu("ltq_dsl", NULL, 0,
|
||||
PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
|
||||
PMU_PPE_QSB | PMU_AHBS | PMU_DFE);
|
||||
} else {
|
||||
clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(),
|
||||
ltq_danube_io_region_clock());
|
||||
clkdev_add_pmu("ltq_dsl", NULL, 0,
|
||||
PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
|
||||
PMU_PPE_QSB | PMU_AHBS | PMU_DFE);
|
||||
}
|
||||
}
|
||||
846
target/linux/lantiq/files/arch/mips/lantiq/xway/timer.c
Normal file
846
target/linux/lantiq/files/arch/mips/lantiq/xway/timer.c
Normal file
@@ -0,0 +1,846 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/div64.h>
|
||||
#include "../clk.h"
|
||||
|
||||
#include <lantiq_soc.h>
|
||||
#include <lantiq_irq.h>
|
||||
#include <lantiq_timer.h>
|
||||
|
||||
#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6
|
||||
|
||||
#ifdef TIMER1A
|
||||
#define FIRST_TIMER TIMER1A
|
||||
#else
|
||||
#define FIRST_TIMER 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GPTC divider is set or not.
|
||||
*/
|
||||
#define GPTU_CLC_RMC_IS_SET 0
|
||||
|
||||
/*
|
||||
* Timer Interrupt (IRQ)
|
||||
*/
|
||||
/* Must be adjusted when ICU driver is available */
|
||||
#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22)
|
||||
|
||||
/*
|
||||
* Bits Operation
|
||||
*/
|
||||
#define GET_BITS(x, msb, lsb) \
|
||||
(((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
|
||||
#define SET_BITS(x, msb, lsb, value) \
|
||||
(((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \
|
||||
(((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
|
||||
|
||||
/*
|
||||
* GPTU Register Mapping
|
||||
*/
|
||||
#define LQ_GPTU (KSEG1 + 0x1E100A00)
|
||||
#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000))
|
||||
#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008))
|
||||
#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4))
|
||||
#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8))
|
||||
#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC))
|
||||
|
||||
/*
|
||||
* Clock Control Register
|
||||
*/
|
||||
#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16)
|
||||
#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8)
|
||||
#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5))
|
||||
#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3))
|
||||
#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2))
|
||||
#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1))
|
||||
#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0))
|
||||
|
||||
#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value))
|
||||
#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value))
|
||||
#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0)
|
||||
#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0)
|
||||
#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0)
|
||||
#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0)
|
||||
#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0)
|
||||
|
||||
/*
|
||||
* ID Register
|
||||
*/
|
||||
#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8)
|
||||
#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5)
|
||||
#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0)
|
||||
|
||||
/*
|
||||
* Control Register of Timer/Counter nX
|
||||
* n is the index of block (1 based index)
|
||||
* X is either A or B
|
||||
*/
|
||||
#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10))
|
||||
#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9))
|
||||
#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8))
|
||||
#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6)
|
||||
#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5))
|
||||
#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */
|
||||
#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3))
|
||||
#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2))
|
||||
#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1))
|
||||
#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0))
|
||||
|
||||
#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10))
|
||||
#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0)
|
||||
#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0)
|
||||
#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value))
|
||||
#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0)
|
||||
#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0)
|
||||
#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0)
|
||||
#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0)
|
||||
#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0)
|
||||
|
||||
#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0)
|
||||
#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0)
|
||||
#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0)
|
||||
|
||||
#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
|
||||
#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
|
||||
|
||||
#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001)
|
||||
#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002)
|
||||
#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004)
|
||||
#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008)
|
||||
#define TIMER_FLAG_NONE_EDGE 0x0000
|
||||
#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030)
|
||||
#define TIMER_FLAG_REAL 0x0000
|
||||
#define TIMER_FLAG_INVERT 0x0040
|
||||
#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040)
|
||||
#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070)
|
||||
#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080)
|
||||
#define TIMER_FLAG_CALLBACK_IN_HB 0x0200
|
||||
#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300)
|
||||
#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000)
|
||||
|
||||
struct timer_dev_timer {
|
||||
unsigned int f_irq_on;
|
||||
unsigned int irq;
|
||||
unsigned int flag;
|
||||
unsigned long arg1;
|
||||
unsigned long arg2;
|
||||
};
|
||||
|
||||
struct timer_dev {
|
||||
struct mutex gptu_mutex;
|
||||
unsigned int number_of_timers;
|
||||
unsigned int occupation;
|
||||
unsigned int f_gptu_on;
|
||||
struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2];
|
||||
};
|
||||
|
||||
unsigned long ltq_danube_fpi_bus_clock(int fpi);
|
||||
unsigned long ltq_vr9_fpi_bus_clock(int fpi);
|
||||
|
||||
unsigned int ltq_get_fpi_bus_clock(int fpi) {
|
||||
if (ltq_is_ase())
|
||||
return CLOCK_133M;
|
||||
else if (ltq_is_vr9())
|
||||
return ltq_vr9_fpi_bus_clock(fpi);
|
||||
|
||||
return ltq_danube_fpi_bus_clock(fpi);
|
||||
}
|
||||
|
||||
|
||||
static long gptu_ioctl(struct file *, unsigned int, unsigned long);
|
||||
static int gptu_open(struct inode *, struct file *);
|
||||
static int gptu_release(struct inode *, struct file *);
|
||||
|
||||
static struct file_operations gptu_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = gptu_ioctl,
|
||||
.open = gptu_open,
|
||||
.release = gptu_release
|
||||
};
|
||||
|
||||
static struct miscdevice gptu_miscdev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "gptu",
|
||||
.fops = &gptu_fops,
|
||||
};
|
||||
|
||||
static struct timer_dev timer_dev;
|
||||
|
||||
static irqreturn_t timer_irq_handler(int irq, void *p)
|
||||
{
|
||||
unsigned int timer;
|
||||
unsigned int flag;
|
||||
struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p;
|
||||
|
||||
timer = irq - TIMER_INTERRUPT;
|
||||
if (timer < timer_dev.number_of_timers
|
||||
&& dev_timer == &timer_dev.timer[timer]) {
|
||||
/* Clear interrupt. */
|
||||
ltq_w32(1 << timer, LQ_GPTU_IRNCR);
|
||||
|
||||
/* Call user hanler or signal. */
|
||||
flag = dev_timer->flag;
|
||||
if (!(timer & 0x01)
|
||||
|| TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
|
||||
/* 16-bit timer or timer A of 32-bit timer */
|
||||
switch (TIMER_FLAG_MASK_HANDLE(flag)) {
|
||||
case TIMER_FLAG_CALLBACK_IN_IRQ:
|
||||
case TIMER_FLAG_CALLBACK_IN_HB:
|
||||
if (dev_timer->arg1)
|
||||
(*(timer_callback)dev_timer->arg1)(dev_timer->arg2);
|
||||
break;
|
||||
case TIMER_FLAG_SIGNAL:
|
||||
send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline void lq_enable_gptu(void)
|
||||
{
|
||||
struct clk *clk = clk_get_sys("ltq_gptu", NULL);
|
||||
clk_enable(clk);
|
||||
|
||||
//ltq_pmu_enable(PMU_GPT);
|
||||
|
||||
/* Set divider as 1, disable write protection for SPEN, enable module. */
|
||||
*LQ_GPTU_CLC =
|
||||
GPTU_CLC_SMC_SET(0x00) |
|
||||
GPTU_CLC_RMC_SET(0x01) |
|
||||
GPTU_CLC_FSOE_SET(0) |
|
||||
GPTU_CLC_SBWE_SET(1) |
|
||||
GPTU_CLC_EDIS_SET(0) |
|
||||
GPTU_CLC_SPEN_SET(0) |
|
||||
GPTU_CLC_DISR_SET(0);
|
||||
}
|
||||
|
||||
static inline void lq_disable_gptu(void)
|
||||
{
|
||||
struct clk *clk = clk_get_sys("ltq_gptu", NULL);
|
||||
ltq_w32(0x00, LQ_GPTU_IRNEN);
|
||||
ltq_w32(0xfff, LQ_GPTU_IRNCR);
|
||||
|
||||
/* Set divider as 0, enable write protection for SPEN, disable module. */
|
||||
*LQ_GPTU_CLC =
|
||||
GPTU_CLC_SMC_SET(0x00) |
|
||||
GPTU_CLC_RMC_SET(0x00) |
|
||||
GPTU_CLC_FSOE_SET(0) |
|
||||
GPTU_CLC_SBWE_SET(0) |
|
||||
GPTU_CLC_EDIS_SET(0) |
|
||||
GPTU_CLC_SPEN_SET(0) |
|
||||
GPTU_CLC_DISR_SET(1);
|
||||
|
||||
clk_enable(clk);
|
||||
}
|
||||
|
||||
int lq_request_timer(unsigned int timer, unsigned int flag,
|
||||
unsigned long value, unsigned long arg1, unsigned long arg2)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int con_reg, irnen_reg;
|
||||
int n, X;
|
||||
|
||||
if (timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
return -EINVAL;
|
||||
|
||||
printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...",
|
||||
timer, flag, value);
|
||||
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT)
|
||||
value &= 0xFFFF;
|
||||
else
|
||||
timer &= ~0x01;
|
||||
|
||||
mutex_lock(&timer_dev.gptu_mutex);
|
||||
|
||||
/*
|
||||
* Allocate timer.
|
||||
*/
|
||||
if (timer < FIRST_TIMER) {
|
||||
unsigned int mask;
|
||||
unsigned int shift;
|
||||
/* This takes care of TIMER1B which is the only choice for Voice TAPI system */
|
||||
unsigned int offset = TIMER2A;
|
||||
|
||||
/*
|
||||
* Pick up a free timer.
|
||||
*/
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
|
||||
mask = 1 << offset;
|
||||
shift = 1;
|
||||
} else {
|
||||
mask = 3 << offset;
|
||||
shift = 2;
|
||||
}
|
||||
for (timer = offset;
|
||||
timer < offset + timer_dev.number_of_timers;
|
||||
timer += shift, mask <<= shift)
|
||||
if (!(timer_dev.occupation & mask)) {
|
||||
timer_dev.occupation |= mask;
|
||||
break;
|
||||
}
|
||||
if (timer >= offset + timer_dev.number_of_timers) {
|
||||
printk("failed![%d]\n", __LINE__);
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EINVAL;
|
||||
} else
|
||||
ret = timer;
|
||||
} else {
|
||||
register unsigned int mask;
|
||||
|
||||
/*
|
||||
* Check if the requested timer is free.
|
||||
*/
|
||||
mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
if ((timer_dev.occupation & mask)) {
|
||||
printk("failed![%d] mask %#x, timer_dev.occupation %#x\n",
|
||||
__LINE__, mask, timer_dev.occupation);
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EBUSY;
|
||||
} else {
|
||||
timer_dev.occupation |= mask;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare control register value.
|
||||
*/
|
||||
switch (TIMER_FLAG_MASK_EDGE(flag)) {
|
||||
default:
|
||||
case TIMER_FLAG_NONE_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x00);
|
||||
break;
|
||||
case TIMER_FLAG_RISE_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x01);
|
||||
break;
|
||||
case TIMER_FLAG_FALL_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x02);
|
||||
break;
|
||||
case TIMER_FLAG_ANY_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x03);
|
||||
break;
|
||||
}
|
||||
if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER)
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_SRC(flag) ==
|
||||
TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) :
|
||||
GPTU_CON_SRC_EXT_SET(0);
|
||||
else
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_SRC(flag) ==
|
||||
TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) :
|
||||
GPTU_CON_SRC_EG_SET(0);
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_SYNC(flag) ==
|
||||
TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) :
|
||||
GPTU_CON_SYNC_SET(1);
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_INVERT(flag) ==
|
||||
TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_SIZE(flag) ==
|
||||
TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) :
|
||||
GPTU_CON_EXT_SET(1);
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_STOP(flag) ==
|
||||
TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_TYPE(flag) ==
|
||||
TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) :
|
||||
GPTU_CON_CNT_SET(1);
|
||||
con_reg |=
|
||||
TIMER_FLAG_MASK_DIR(flag) ==
|
||||
TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
|
||||
|
||||
/*
|
||||
* Fill up running data.
|
||||
*/
|
||||
timer_dev.timer[timer - FIRST_TIMER].flag = flag;
|
||||
timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1;
|
||||
timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2;
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag;
|
||||
|
||||
/*
|
||||
* Enable GPTU module.
|
||||
*/
|
||||
if (!timer_dev.f_gptu_on) {
|
||||
lq_enable_gptu();
|
||||
timer_dev.f_gptu_on = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable IRQ.
|
||||
*/
|
||||
if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) {
|
||||
if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL)
|
||||
timer_dev.timer[timer - FIRST_TIMER].arg1 =
|
||||
(unsigned long) find_task_by_vpid((int) arg1);
|
||||
|
||||
irnen_reg = 1 << (timer - FIRST_TIMER);
|
||||
|
||||
if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL
|
||||
|| (TIMER_FLAG_MASK_HANDLE(flag) ==
|
||||
TIMER_FLAG_CALLBACK_IN_IRQ
|
||||
&& timer_dev.timer[timer - FIRST_TIMER].arg1)) {
|
||||
enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
|
||||
timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1;
|
||||
}
|
||||
} else
|
||||
irnen_reg = 0;
|
||||
|
||||
/*
|
||||
* Write config register, reload value and enable interrupt.
|
||||
*/
|
||||
n = timer >> 1;
|
||||
X = timer & 0x01;
|
||||
*LQ_GPTU_CON(n, X) = con_reg;
|
||||
*LQ_GPTU_RELOAD(n, X) = value;
|
||||
/* printk("reload value = %d\n", (u32)value); */
|
||||
*LQ_GPTU_IRNEN |= irnen_reg;
|
||||
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
printk("successful!\n");
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_request_timer);
|
||||
|
||||
int lq_free_timer(unsigned int timer)
|
||||
{
|
||||
unsigned int flag;
|
||||
unsigned int mask;
|
||||
int n, X;
|
||||
|
||||
if (!timer_dev.f_gptu_on)
|
||||
return -EINVAL;
|
||||
|
||||
if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&timer_dev.gptu_mutex);
|
||||
|
||||
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
timer &= ~0x01;
|
||||
|
||||
mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = timer >> 1;
|
||||
X = timer & 0x01;
|
||||
|
||||
if (GPTU_CON_EN(n, X))
|
||||
*LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
|
||||
|
||||
*LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1);
|
||||
*LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1);
|
||||
|
||||
if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) {
|
||||
disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
|
||||
timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0;
|
||||
}
|
||||
|
||||
timer_dev.occupation &= ~mask;
|
||||
if (!timer_dev.occupation && timer_dev.f_gptu_on) {
|
||||
lq_disable_gptu();
|
||||
timer_dev.f_gptu_on = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_free_timer);
|
||||
|
||||
int lq_start_timer(unsigned int timer, int is_resume)
|
||||
{
|
||||
unsigned int flag;
|
||||
unsigned int mask;
|
||||
int n, X;
|
||||
|
||||
if (!timer_dev.f_gptu_on)
|
||||
return -EINVAL;
|
||||
|
||||
if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&timer_dev.gptu_mutex);
|
||||
|
||||
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
timer &= ~0x01;
|
||||
|
||||
mask = (TIMER_FLAG_MASK_SIZE(flag) ==
|
||||
TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = timer >> 1;
|
||||
X = timer & 0x01;
|
||||
|
||||
*LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1);
|
||||
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_start_timer);
|
||||
|
||||
int lq_stop_timer(unsigned int timer)
|
||||
{
|
||||
unsigned int flag;
|
||||
unsigned int mask;
|
||||
int n, X;
|
||||
|
||||
if (!timer_dev.f_gptu_on)
|
||||
return -EINVAL;
|
||||
|
||||
if (timer < FIRST_TIMER
|
||||
|| timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&timer_dev.gptu_mutex);
|
||||
|
||||
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
timer &= ~0x01;
|
||||
|
||||
mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = timer >> 1;
|
||||
X = timer & 0x01;
|
||||
|
||||
*LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
|
||||
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_stop_timer);
|
||||
|
||||
int lq_reset_counter_flags(u32 timer, u32 flags)
|
||||
{
|
||||
unsigned int oflag;
|
||||
unsigned int mask, con_reg;
|
||||
int n, X;
|
||||
|
||||
if (!timer_dev.f_gptu_on)
|
||||
return -EINVAL;
|
||||
|
||||
if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&timer_dev.gptu_mutex);
|
||||
|
||||
oflag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT)
|
||||
timer &= ~0x01;
|
||||
|
||||
mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (TIMER_FLAG_MASK_EDGE(flags)) {
|
||||
default:
|
||||
case TIMER_FLAG_NONE_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x00);
|
||||
break;
|
||||
case TIMER_FLAG_RISE_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x01);
|
||||
break;
|
||||
case TIMER_FLAG_FALL_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x02);
|
||||
break;
|
||||
case TIMER_FLAG_ANY_EDGE:
|
||||
con_reg = GPTU_CON_EDGE_SET(0x03);
|
||||
break;
|
||||
}
|
||||
if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER)
|
||||
con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0);
|
||||
else
|
||||
con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0);
|
||||
con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1);
|
||||
con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
|
||||
con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1);
|
||||
con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
|
||||
con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1);
|
||||
con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
|
||||
|
||||
timer_dev.timer[timer - FIRST_TIMER].flag = flags;
|
||||
if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT)
|
||||
timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags;
|
||||
|
||||
n = timer >> 1;
|
||||
X = timer & 0x01;
|
||||
|
||||
*LQ_GPTU_CON(n, X) = con_reg;
|
||||
smp_wmb();
|
||||
printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X));
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_reset_counter_flags);
|
||||
|
||||
int lq_get_count_value(unsigned int timer, unsigned long *value)
|
||||
{
|
||||
unsigned int flag;
|
||||
unsigned int mask;
|
||||
int n, X;
|
||||
|
||||
if (!timer_dev.f_gptu_on)
|
||||
return -EINVAL;
|
||||
|
||||
if (timer < FIRST_TIMER
|
||||
|| timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&timer_dev.gptu_mutex);
|
||||
|
||||
flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
timer &= ~0x01;
|
||||
|
||||
mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = timer >> 1;
|
||||
X = timer & 0x01;
|
||||
|
||||
*value = *LQ_GPTU_COUNT(n, X);
|
||||
|
||||
mutex_unlock(&timer_dev.gptu_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_get_count_value);
|
||||
|
||||
u32 lq_cal_divider(unsigned long freq)
|
||||
{
|
||||
u64 module_freq, fpi = ltq_get_fpi_bus_clock(2);
|
||||
u32 clock_divider = 1;
|
||||
module_freq = fpi * 1000;
|
||||
do_div(module_freq, clock_divider * freq);
|
||||
return module_freq;
|
||||
}
|
||||
EXPORT_SYMBOL(lq_cal_divider);
|
||||
|
||||
int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic,
|
||||
int is_ext_src, unsigned int handle_flag, unsigned long arg1,
|
||||
unsigned long arg2)
|
||||
{
|
||||
unsigned long divider;
|
||||
unsigned int flag;
|
||||
|
||||
divider = lq_cal_divider(freq);
|
||||
if (divider == 0)
|
||||
return -EINVAL;
|
||||
flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT)
|
||||
| (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE)
|
||||
| (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC)
|
||||
| TIMER_FLAG_TIMER | TIMER_FLAG_DOWN
|
||||
| TIMER_FLAG_MASK_HANDLE(handle_flag);
|
||||
|
||||
printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n",
|
||||
timer, freq, divider);
|
||||
return lq_request_timer(timer, flag, divider, arg1, arg2);
|
||||
}
|
||||
EXPORT_SYMBOL(lq_set_timer);
|
||||
|
||||
int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload,
|
||||
unsigned long arg1, unsigned long arg2)
|
||||
{
|
||||
printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload);
|
||||
return lq_request_timer(timer, flag, reload, arg1, arg2);
|
||||
}
|
||||
EXPORT_SYMBOL(lq_set_counter);
|
||||
|
||||
static long gptu_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
struct gptu_ioctl_param param;
|
||||
|
||||
if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param)))
|
||||
return -EFAULT;
|
||||
copy_from_user(¶m, (void *) arg, sizeof(param));
|
||||
|
||||
if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER
|
||||
|| GPTU_SET_COUNTER) && param.timer < 2)
|
||||
|| cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER)
|
||||
&& !access_ok(VERIFY_WRITE, arg,
|
||||
sizeof(struct gptu_ioctl_param)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmd) {
|
||||
case GPTU_REQUEST_TIMER:
|
||||
ret = lq_request_timer(param.timer, param.flag, param.value,
|
||||
(unsigned long) param.pid,
|
||||
(unsigned long) param.sig);
|
||||
if (ret > 0) {
|
||||
copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
timer, &ret, sizeof(&ret));
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case GPTU_FREE_TIMER:
|
||||
ret = lq_free_timer(param.timer);
|
||||
break;
|
||||
case GPTU_START_TIMER:
|
||||
ret = lq_start_timer(param.timer, param.flag);
|
||||
break;
|
||||
case GPTU_STOP_TIMER:
|
||||
ret = lq_stop_timer(param.timer);
|
||||
break;
|
||||
case GPTU_GET_COUNT_VALUE:
|
||||
ret = lq_get_count_value(param.timer, ¶m.value);
|
||||
if (!ret)
|
||||
copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
value, ¶m.value,
|
||||
sizeof(param.value));
|
||||
break;
|
||||
case GPTU_CALCULATE_DIVIDER:
|
||||
param.value = lq_cal_divider(param.value);
|
||||
if (param.value == 0)
|
||||
ret = -EINVAL;
|
||||
else {
|
||||
copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
value, ¶m.value,
|
||||
sizeof(param.value));
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case GPTU_SET_TIMER:
|
||||
ret = lq_set_timer(param.timer, param.value,
|
||||
TIMER_FLAG_MASK_STOP(param.flag) !=
|
||||
TIMER_FLAG_ONCE ? 1 : 0,
|
||||
TIMER_FLAG_MASK_SRC(param.flag) ==
|
||||
TIMER_FLAG_EXT_SRC ? 1 : 0,
|
||||
TIMER_FLAG_MASK_HANDLE(param.flag) ==
|
||||
TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL :
|
||||
TIMER_FLAG_NO_HANDLE,
|
||||
(unsigned long) param.pid,
|
||||
(unsigned long) param.sig);
|
||||
if (ret > 0) {
|
||||
copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
timer, &ret, sizeof(&ret));
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case GPTU_SET_COUNTER:
|
||||
lq_set_counter(param.timer, param.flag, param.value, 0, 0);
|
||||
if (ret > 0) {
|
||||
copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
timer, &ret, sizeof(&ret));
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gptu_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gptu_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init lq_gptu_init(void)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i;
|
||||
|
||||
ltq_w32(0, LQ_GPTU_IRNEN);
|
||||
ltq_w32(0xfff, LQ_GPTU_IRNCR);
|
||||
|
||||
memset(&timer_dev, 0, sizeof(timer_dev));
|
||||
mutex_init(&timer_dev.gptu_mutex);
|
||||
|
||||
lq_enable_gptu();
|
||||
timer_dev.number_of_timers = GPTU_ID_CFG * 2;
|
||||
lq_disable_gptu();
|
||||
if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2)
|
||||
timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2;
|
||||
printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers);
|
||||
|
||||
ret = misc_register(&gptu_miscdev);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret);
|
||||
return ret;
|
||||
} else {
|
||||
printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor);
|
||||
}
|
||||
|
||||
for (i = 0; i < timer_dev.number_of_timers; i++) {
|
||||
ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]);
|
||||
if (ret) {
|
||||
for (; i >= 0; i--)
|
||||
free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]);
|
||||
misc_deregister(&gptu_miscdev);
|
||||
printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret);
|
||||
return ret;
|
||||
} else {
|
||||
timer_dev.timer[i].irq = TIMER_INTERRUPT + i;
|
||||
disable_irq(timer_dev.timer[i].irq);
|
||||
printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit lq_gptu_exit(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < timer_dev.number_of_timers; i++) {
|
||||
if (timer_dev.timer[i].f_irq_on)
|
||||
disable_irq(timer_dev.timer[i].irq);
|
||||
free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]);
|
||||
}
|
||||
lq_disable_gptu();
|
||||
misc_deregister(&gptu_miscdev);
|
||||
}
|
||||
|
||||
module_init(lq_gptu_init);
|
||||
module_exit(lq_gptu_exit);
|
||||
Reference in New Issue
Block a user