* backport 2.6.8 patches to .39 / .32.33

* remove lqtapi
* bump tapi/dsl to .39
* migrate to new ltq_ style api
* add amazon_se support

SVN-Revision: 27026
This commit is contained in:
John Crispin 2011-05-29 21:19:26 +00:00
parent c7cdee0230
commit 6608f419d1
165 changed files with 54110 additions and 18452 deletions

View file

@ -1,73 +0,0 @@
#
# Copyright (C) 2006-2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=lqtapi
PKG_VERSION:=1
PKG_RELEASE:=1
FW_SOURCE:=danube_firmware.bin
FW_URL:=http://www.arcor.de/hilfe/files/pdf/
FW_FILE=arcor_A800_452CPW_FW_1.02.206(20081201).bin
FW_MD5SUM:=19d9af4e369287a0f0abaed415cdac10
include $(INCLUDE_DIR)/package.mk
define Download/firmware
FILE:=$(FW_FILE)
URL:=$(FW_URL)
MD5SUM:=$(FW_MD5SUM)
endef
$(eval $(call Download,firmware))
define KernelPackage/lqtapi
SUBMENU:=Voice over IP
TITLE:=Tapi drivers for Lantiq SoC
DEPENDS:=@TARGET_lantiq_xway @BROKEN
FILES:=$(PKG_BUILD_DIR)/tapi/tapi.ko \
$(PKG_BUILD_DIR)/mps/mps.ko \
$(PKG_BUILD_DIR)/mps/vmmc.ko
AUTOLOAD:=$(call AutoLoad,80,tapi) \
$(call AutoLoad,81,mps)
endef
define Package/lqtapi-firmware-danube
SECTION:=sys
CATEGORY:=Kernel modules
SUBMENU:=Voice over IP
TITLE:=Danube firmware
DEPENDS:=+kmod-lqtapi
endef
include $(INCLUDE_DIR)/kernel-defaults.mk
define KernelPackage/lqtapi/description
FOSS drivers for Lantiq SoC voip core
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) $(KERNEL_MAKEOPTS) \
SUBDIRS="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS=-I$(PKG_BUILD_DIR)/include/ \
modules
endef
define Package/lqtapi-firmware-danube/install
$(TOPDIR)/target/linux/$(BOARD)/extract.sh $(DL_DIR) '$(FW_FILE)'
$(INSTALL_DIR) $(1)/lib/firmware/
$(INSTALL_DATA) $(DL_DIR)/voip.bin $(1)/lib/firmware/$(FW_SOURCE)
endef
$(eval $(call KernelPackage,lqtapi))
$(eval $(call BuildPackage,lqtapi-firmware-danube))

View file

@ -1 +0,0 @@
obj-m = tapi/ mps/

View file

@ -1,37 +0,0 @@
#ifndef __LINUX_TAPI_TAPI_EVENT_H__
#define __LINUX_TAPI_TAPI_EVENT_H__
struct tapi_device;
struct tapi_port;
struct tapi_hook_event {
bool on;
};
struct tapi_dtmf_event {
unsigned char code;
};
enum tapi_event_type {
TAPI_EVENT_TYPE_HOOK,
TAPI_EVENT_TYPE_DTMF,
};
struct tapi_event {
struct timeval time;
enum tapi_event_type type;
unsigned int port;
union {
struct tapi_hook_event hook;
struct tapi_dtmf_event dtmf;
};
};
void tapi_report_event(struct tapi_device *tdev, struct tapi_event *event);
void tapi_report_hook_event(struct tapi_device *tdev, struct tapi_port *port,
bool on);
void tapi_report_dtmf_event(struct tapi_device *tdev, struct tapi_port *port,
unsigned char code);
#endif

View file

@ -1,20 +0,0 @@
#include <linux/ioctl.h>
#define TAPI_MAGIC 't'
#define TAPI_IOCTL(x) _IO(TAPI_MAGIC, (x))
#define TAPI_CONTROL_IOCTL_LINK_ALLOC TAPI_IOCTL(0)
#define TAPI_CONTROL_IOCTL_LINK_FREE TAPI_IOCTL(1)
#define TAPI_CONTROL_IOCTL_LINK_ENABLE TAPI_IOCTL(2)
#define TAPI_CONTROL_IOCTL_LINK_DISABLE TAPI_IOCTL(3)
#define TAPI_CONTROL_IOCTL_SYNC TAPI_IOCTL(4)
#define TAPI_PORT_IOCTL_GET_ENDPOINT TAPI_IOCTL(5)
#define TAPI_PORT_IOCTL_SET_RING TAPI_IOCTL(6)
#define TAPI_STREAM_IOCTL_GET_ENDPOINT TAPI_IOCTL(7)
#define TAPI_STREAM_IOCTL_CONFIGURE TAPI_IOCTL(8)
#define TAPI_STREAM_IOCTL_START TAPI_IOCTL(9)
#define TAPI_STREAM_IOCTL_STOP TAPI_IOCTL(10)

View file

@ -1,231 +0,0 @@
#ifndef __LINUX_TAPI_H__
#define __LINUX_TAPI_H__
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/input.h>
#include <asm/atomic.h>
#include <linux/list.h>
#include <linux/cdev.h>
#include <linux/skbuff.h>
#include <linux/wait.h>
#include <linux/tapi/tapi-event.h>
struct tapi_device;
struct tapi_char_device {
struct tapi_device *tdev;
struct device dev;
struct cdev cdev;
};
static inline struct tapi_char_device *cdev_to_tapi_char_device(struct cdev *cdev)
{
return container_of(cdev, struct tapi_char_device, cdev);
}
int tapi_char_device_register(struct tapi_device *tdev,
struct tapi_char_device *tchrdev, const struct file_operations *fops);
struct tapi_endpoint {
unsigned int id;
void *data;
};
static inline void tapi_endpoint_set_data(struct tapi_endpoint *ep, void *data)
{
ep->data = data;
}
static inline void *tapi_endpoint_get_data(struct tapi_endpoint *ep)
{
return ep->data;
}
struct tapi_port {
unsigned int id;
struct tapi_endpoint ep;
struct input_dev *input;
struct tapi_char_device chrdev;
};
struct tapi_stream {
unsigned int id;
struct list_head head;
struct tapi_endpoint ep;
struct sk_buff_head recv_queue;
wait_queue_head_t recv_wait;
struct sk_buff_head send_queue;
};
struct tapi_link {
unsigned int id;
struct list_head head;
};
enum tapi_codec {
TAPI_CODEC_L16,
};
struct tapi_stream_config {
enum tapi_codec codec;
unsigned int buffer_size;
};
struct tapi_ops {
int (*send_dtmf_events)(struct tapi_device *, struct tapi_port *port,
struct tapi_dtmf_event *, size_t num_events, unsigned int dealy);
int (*send_dtmf_event)(struct tapi_device *, struct tapi_port *port,
struct tapi_dtmf_event *);
int (*ring)(struct tapi_device *, struct tapi_port *port, bool ring);
struct tapi_stream *(*stream_alloc)(struct tapi_device *);
void (*stream_free)(struct tapi_device *, struct tapi_stream *);
int (*stream_configure)(struct tapi_device *, struct tapi_stream *,
struct tapi_stream_config *);
int (*stream_start)(struct tapi_device *, struct tapi_stream *);
int (*stream_stop)(struct tapi_device *, struct tapi_stream *);
int (*stream_send)(struct tapi_device *, struct tapi_stream *,
struct sk_buff *);
struct tapi_link *(*link_alloc)(struct tapi_device *,
struct tapi_endpoint *ep1, struct tapi_endpoint *ep2);
void (*link_free)(struct tapi_device *, struct tapi_link *);
int (*link_enable)(struct tapi_device *, struct tapi_link *);
int (*link_disable)(struct tapi_device *, struct tapi_link *);
int (*sync)(struct tapi_device *);
};
int tapi_stream_recv(struct tapi_device *, struct tapi_stream *, struct sk_buff *);
struct tapi_device {
unsigned int id;
const struct tapi_ops *ops;
unsigned int num_ports;
struct device dev;
struct mutex lock;
struct tapi_port *ports;
struct list_head streams;
struct list_head links;
atomic_t stream_id;
atomic_t link_id;
struct tapi_char_device stream_dev;
struct tapi_char_device control_dev;
};
static inline struct tapi_device *dev_to_tapi(struct device *dev)
{
return container_of(dev, struct tapi_device, dev);
}
static inline struct tapi_stream *tapi_stream_from_id(struct tapi_device *tdev,
unsigned int id)
{
struct tapi_stream *stream;
mutex_lock(&tdev->lock);
list_for_each_entry(stream, &tdev->streams, head) {
if (stream->id == id)
goto out;
}
stream = NULL;
out:
mutex_unlock(&tdev->lock);
return stream;
}
struct tapi_link *tapi_link_alloc(struct tapi_device *, struct tapi_endpoint *,
struct tapi_endpoint *);
void tapi_link_free(struct tapi_device *, struct tapi_link *);
struct tapi_stream *tapi_stream_alloc(struct tapi_device *tdev);
void tapi_stream_free(struct tapi_device *tdev, struct tapi_stream *stream);
static inline int tapi_sync(struct tapi_device *tdev)
{
if (!tdev->ops || !tdev->ops->sync)
return 0;
return tdev->ops->sync(tdev);
}
static inline int tapi_link_enable(struct tapi_device *tdev,
struct tapi_link *link)
{
if (!tdev->ops || !tdev->ops->link_enable)
return 0;
return tdev->ops->link_enable(tdev, link);
}
static inline int tapi_link_disable(struct tapi_device *tdev,
struct tapi_link *link)
{
if (!tdev->ops || !tdev->ops->link_disable)
return 0;
return tdev->ops->link_disable(tdev, link);
}
static inline int tapi_port_send_dtmf(struct tapi_device *tdev,
struct tapi_port *port, struct tapi_dtmf_event *dtmf)
{
if (!tdev->ops || !tdev->ops->send_dtmf_event)
return -ENOSYS;
return tdev->ops->send_dtmf_event(tdev, port, dtmf);
}
static inline int tapi_port_set_ring(struct tapi_device *tdev,
struct tapi_port *port, bool ring)
{
if (!tdev->ops || !tdev->ops->ring)
return -ENOSYS;
return tdev->ops->ring(tdev, port, ring);
}
static inline int tapi_stream_start(struct tapi_device *tdev,
struct tapi_stream *stream)
{
if (!tdev->ops || !tdev->ops->stream_start)
return -ENOSYS;
return tdev->ops->stream_start(tdev, stream);
}
static inline int tapi_stream_stop(struct tapi_device *tdev,
struct tapi_stream *stream)
{
if (!tdev->ops || !tdev->ops->stream_stop)
return -ENOSYS;
return tdev->ops->stream_stop(tdev, stream);
}
int tapi_device_register(struct tapi_device *tdev, const char *name,
struct device *parent);
void tapi_device_unregister(struct tapi_device *tdev);
struct tapi_sysfs_port;
struct tapi_sysfs_port *tapi_port_alloc(struct tapi_device *tdev, unsigned int id);
void tapi_port_delete(struct tapi_sysfs_port *);
#endif

View file

@ -1,8 +0,0 @@
mps-objs := mps-core.o mps-irq.o mps-fifo.o
obj-m += mps.o
vmmc-objs := vmmc-core.o vmmc-alm.o vmmc-module.o vmmc-link.o vmmc-port.o \
vmmc-signal.o vmmc-stream.o vmmc-coder.o
obj-m += vmmc.o

View file

@ -1,238 +0,0 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <ifxmips.h>
#include <ifxmips_cgu.h>
#include <ifxmips_prom.h>
#include <ifxmips_irq.h>
#include "mps.h"
extern int mps_irq_init(struct mps *mps);
extern void mps_irq_exit(struct mps *mps);
#define MPS_CPU0_BOOT_RVEC 0x1c0
#define MPS_CPU0_BOOT_NVEC 0x1c4
#define MPS_CPU0_BOOT_EVEC 0x1c8
#define MPS_CPU0_CP0_STATUS 0x1cc
#define MPS_CPU0_CP0_EEPC 0x1d0
#define MPS_CPU0_CP0_EPC 0x1d4
#define MPS_CPU0_BOOT_SIZE 0x1d8
#define MPS_CPU0_CFG_STAT 0x1dc
#define MPS_CPU1_BOOT_RVEC 0x1e0
#define MPS_CPU1_BOOT_NVEC 0x1e4
#define MPS_CPU1_BOOT_EVEC 0x1e8
#define MPS_CPU1_CP0_STATUS 0x1ec
#define MPS_CPU1_CP0_EEPC 0x1f0
#define MPS_CPU1_CP0_EPC 0x1f4
#define MPS_CPU1_BOOT_SIZE 0x1f8
#define MPS_CPU1_CFG_STAT 0x1fc
static void mps_reset(void)
{
ifxmips_w32(ifxmips_r32(IFXMIPS_RCU_RST) | IFXMIPS_RCU_RST_CPU1,
IFXMIPS_RCU_RST);
smp_wmb();
}
static void mps_release(void)
{
uint32_t val;
val = ifxmips_r32(IFXMIPS_RCU_RST);
val |= 0x20000000;
val &= ~IFXMIPS_RCU_RST_CPU1;
ifxmips_w32(val, IFXMIPS_RCU_RST);
smp_wmb();
}
void mps_load_firmware(struct mps *mps, const void *data, size_t size,
enum mps_boot_config config)
{
uint32_t cfg = 0;
uint32_t fw_size = size;
if (config == MPS_BOOT_LEGACY) {
cfg = 0x00020000;
fw_size -= sizeof(uint32_t);
} else {
if(config == MPS_BOOT_ENCRYPTED) {
cfg = __raw_readl(mps->mbox_base + MPS_CPU1_CFG_STAT);
cfg |= 0x00700000;
} else {
printk("PANIC!\n");
}
}
mps_reset();
memcpy_toio(mps->cp1_base, data, size);
__raw_writel(cfg, mps->mbox_base + MPS_CPU1_CFG_STAT);
__raw_writel(fw_size, mps->mbox_base + MPS_CPU1_BOOT_SIZE);
__raw_writel((uint32_t)mps->cp1_base, mps->mbox_base + MPS_CPU1_BOOT_RVEC);
mps_release();
}
EXPORT_SYMBOL_GPL(mps_load_firmware);
void mps_configure_fifo(struct mps *mps, struct mps_fifo *fifo,
const struct mps_fifo_config *config)
{
mps_fifo_init(fifo, mps->mbox_base + config->base,
mps->mbox_base + config->head_addr,
mps->mbox_base + config->tail_addr,
config->size);
__raw_writel(config->size, mps->mbox_base + config->size_addr);
__raw_writel(mps->mbox_res->start + config->base,
mps->mbox_base + config->base_addr);
}
EXPORT_SYMBOL_GPL(mps_configure_fifo);
void mps_configure_mailbox(struct mps *mps, struct mps_mailbox *mbox,
const struct mps_fifo_config *upstream_config,
const struct mps_fifo_config *downstream_config)
{
mps_configure_fifo(mps, &mbox->upstream, upstream_config);
mps_configure_fifo(mps, &mbox->downstream, downstream_config);
}
EXPORT_SYMBOL_GPL(mps_configure_mailbox);
static int __devinit mps_probe(struct platform_device *pdev)
{
int ret;
struct mps *mps;
struct resource *res;
mps = kzalloc(sizeof(*mps), GFP_KERNEL);
if (!mps)
return -ENOMEM;
mps->dev = &pdev->dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
if (!res) {
dev_err(&pdev->dev, "Failed to get mem resource");
ret = -ENOENT;
goto err_free;
}
res = request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev));
if (!res) {
dev_err(&pdev->dev, "Failed to request mem resource");
ret = -EBUSY;
goto err_free;
}
mps->base = ioremap_nocache(res->start, resource_size(res));
if (!mps->base) {
dev_err(&pdev->dev, "Failed to ioremap mem region\n");
ret = -EBUSY;
goto err_release_mem_region;
}
mps->res = res;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mailbox");
if (!res) {
dev_err(&pdev->dev, "Failed to get mailbox mem region\n");
ret = -ENOENT;
goto err_free;
}
res = request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev));
if (!res) {
dev_err(&pdev->dev, "Failed to request mailbox mem region\n");
ret = -EBUSY;
goto err_free;
}
mps->mbox_base = ioremap_nocache(res->start, resource_size(res));
if (!mps->mbox_base) {
dev_err(&pdev->dev, "Failed to ioremap mailbox mem region\n");
ret = -EBUSY;
goto err_release_mem_region;
}
mps->mbox_res = res;
mps->cp1_base = ioremap_nocache((unsigned int)pdev->dev.platform_data, 1 << 20);
if (!mps->cp1_base) {
dev_err(&pdev->dev, "Failed to ioremap cp1 address\n");
ret = -EBUSY;
goto err_release_mem_region;
}
mps->irq_ad0 = INT_NUM_IM4_IRL18;
mps->irq_ad1 = INT_NUM_IM4_IRL19;
mps->irq_base = 160;
ret = mps_irq_init(mps);
if (ret < 0)
goto err_iounmap;
platform_set_drvdata(pdev, mps);
return 0;
err_iounmap:
iounmap(mps->mbox_base);
err_release_mem_region:
release_mem_region(res->start, resource_size(res));
err_free:
kfree(mps);
return ret;
}
static int __devexit mps_remove(struct platform_device *pdev)
{
struct mps *mps = platform_get_drvdata(pdev);
mps_irq_exit(mps);
iounmap(mps->mbox_base);
release_mem_region(mps->mbox_res->start, resource_size(mps->mbox_res));
iounmap(mps->base);
release_mem_region(mps->res->start, resource_size(mps->res));
kfree(mps);
return 0;
}
static struct platform_driver mps_driver = {
.probe = mps_probe,
.remove = __devexit_p(mps_remove),
.driver = {
.name = "mps",
.owner = THIS_MODULE
},
};
static int __init mps_init(void)
{
return platform_driver_register(&mps_driver);
}
module_init(mps_init);
static void __exit mps_exit(void)
{
platform_driver_unregister(&mps_driver);
}
module_exit(mps_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");

View file

@ -1,102 +0,0 @@
#include <linux/io.h>
#include "mps.h"
void mps_fifo_init(struct mps_fifo *fifo, void __iomem *base,
void __iomem *head_addr, void __iomem *tail_addr, uint32_t size)
{
fifo->base = base;
fifo->head_addr = head_addr;
fifo->tail_addr = tail_addr;
fifo->size = size;
mps_fifo_reset(fifo);
}
void mps_fifo_in(struct mps_fifo *fifo, const uint32_t *from, size_t len)
{
uint32_t head = __raw_readl(fifo->head_addr);
void __iomem *base = fifo->base + head;
size_t i = 0;
size_t byte_len = len * 4;
if (head < byte_len) {
for(; i <= head / 4; ++i) {
__raw_writel(from[i], base);
base -= 4;
}
base += fifo->size;
head += fifo->size;
}
for(; i < len; ++i) {
__raw_writel(from[i], base);
base -= 4;
}
head -= byte_len;
__raw_writel(head, fifo->head_addr);
}
EXPORT_SYMBOL_GPL(mps_fifo_in);
void mps_fifo_out(struct mps_fifo *fifo, uint32_t *to, size_t len)
{
uint32_t tail = __raw_readl(fifo->tail_addr);
void __iomem *base = fifo->base + tail;
size_t i = 0;
size_t byte_len = len * 4;
if (tail < byte_len) {
for(; i <= tail / 4; ++i) {
to[i] = __raw_readl(base);
base -= 4;
}
base += fifo->size;
tail += fifo->size;
}
for(; i < len; ++i) {
to[i] = __raw_readl(base);
base -= 4;
}
tail -= byte_len;
__raw_writel(tail, fifo->tail_addr);
}
EXPORT_SYMBOL_GPL(mps_fifo_out);
uint32_t mps_fifo_peek(struct mps_fifo *fifo)
{
uint32_t tail = __raw_readl(fifo->tail_addr);
void __iomem *base = fifo->base + tail;
return __raw_readl(base);
}
void mps_fifo_reset(struct mps_fifo *fifo)
{
void __iomem *base = fifo->base + fifo->size - 4;
size_t i;
__raw_writel(fifo->size - 4, fifo->head_addr);
__raw_writel(fifo->size - 4, fifo->tail_addr);
for(i = 0; i < 16; ++i) {
__raw_writel(0x0, base);
base -= 4;
}
}
size_t mps_fifo_len(struct mps_fifo *fifo)
{
uint32_t head = __raw_readl(fifo->head_addr);
uint32_t tail = __raw_readl(fifo->tail_addr);
if (tail < head)
return head - tail;
else
return fifo->size - (tail - head);
}
EXPORT_SYMBOL_GPL(mps_fifo_len);

View file

@ -1,157 +0,0 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <ifxmips_irq.h>
#include "mps.h"
#include "mps-irq.h"
#define MPS_REG_AD0_IRQ_BASE 0x40
#define MPS_REG_AD1_IRQ_BASE 0x44
#define MPS_REG_AD_IRQ_STATUS 0x00
#define MPS_REG_AD_IRQ_SET 0x08
#define MPS_REG_AD_IRQ_CLEAR 0x10
#define MPS_REG_AD_IRQ_ENABLE 0x18
struct mps_irq_desc
{
void __iomem *base;
unsigned int irq_base;
};
static inline unsigned int mps_irq_bit(struct mps_irq_desc *mps_desc, int irq)
{
return BIT(irq - mps_desc->irq_base);
}
static void mps_irq_ack(unsigned int irq)
{
struct mps_irq_desc *mps_desc = get_irq_chip_data(irq);
__raw_writel(mps_irq_bit(mps_desc, irq),
mps_desc->base + MPS_REG_AD_IRQ_CLEAR);
}
static void mps_irq_mask(unsigned int irq)
{
struct mps_irq_desc *mps_desc = get_irq_chip_data(irq);
uint32_t mask;
mask = __raw_readl(mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
mask &= ~mps_irq_bit(mps_desc, irq);
__raw_writel(mask, mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
}
static void mps_irq_unmask(unsigned int irq)
{
struct mps_irq_desc *mps_desc = get_irq_chip_data(irq);
uint32_t mask;
mask = __raw_readl(mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
mask |= mps_irq_bit(mps_desc, irq) | 0xffff;
__raw_writel(mask, mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
}
static struct irq_chip mps_irq_chip = {
.name = "mps",
.ack = mps_irq_ack,
.mask = mps_irq_mask,
.unmask = mps_irq_unmask,
};
static void mps_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
{
struct mps_irq_desc *mps_desc = get_irq_data(irq);
uint32_t val;
int mps_irq;
desc->chip->mask(irq);
val = __raw_readl(mps_desc->base + MPS_REG_AD_IRQ_STATUS);
mps_irq = ffs(val);
/* printk("irq: %d %x\n", mps_irq, val);*/
if (mps_irq > 16)
printk("PANIC!\n");
if (mps_irq)
generic_handle_irq(mps_irq + mps_desc->irq_base - 1);
desc->chip->ack(irq);
desc->chip->unmask(irq);
}
#if 0
static const uint32_t ring_msg[] = {
0x01010004, 0x00030000,
};
static irqreturn_t mps_irq_ad0(int irq, void *devid)
{
struct mps *mps = devid;
uint32_t val;
val = __raw_readl(mps->base + MPS_REG_AD0_IRQ_STATUS);
printk("WOHO ein IRQ: %x\n", val);
__raw_writel(val, mps->base + MPS_REG_AD0_IRQ_CLEAR);
if (val & BIT(MPS_IRQ_DOWNLOAD_DONE))
complete(&mps->init_completion);
if (val & BIT(MPS_IRQ_EVENT))
mps_fifo_in(&mps->mbox_cmd.downstream, ring_msg, ARRAY_SIZE(ring_msg));
return IRQ_HANDLED;
}
#endif
#define MPS_NUM_AD_IRQS 32
struct mps_irq_desc mps_irq_descs[2];
int mps_irq_init(struct mps *mps)
{
int ret = 0;
int irq;
mps_irq_descs[0].base = mps->base + MPS_REG_AD0_IRQ_BASE;
mps_irq_descs[0].irq_base = mps->irq_base;
mps_irq_descs[1].base = mps->base + MPS_REG_AD1_IRQ_BASE;
mps_irq_descs[1].irq_base = mps->irq_base + 16;
set_irq_data(mps->irq_ad0, &mps_irq_descs[0]);
set_irq_chained_handler(mps->irq_ad0, mps_irq_demux_handler);
set_irq_data(mps->irq_ad1, &mps_irq_descs[1]);
set_irq_chained_handler(mps->irq_ad1, mps_irq_demux_handler);
/*
ret = request_irq(mps->irq_ad0, mps_irq_demux_handler, IRQF_DISABLED,
"mps ad0", &mps_irq_descs[0]);
ret = request_irq(mps->irq_ad1, mps_irq_demux_handler, IRQF_DISABLED,
"mps ad0", &mps_irq_descs[1]);
*/
for (irq = 0; irq < MPS_NUM_AD_IRQS; ++irq) {
set_irq_chip_data(irq + mps->irq_base, &mps_irq_descs[irq / 16]);
set_irq_chip_and_handler(irq + mps->irq_base, &mps_irq_chip, handle_level_irq);
}
/*
res = request_irq(INT_NUM_IM4_IRL18, mps_irq_ad0, IRQF_DISABLED,
"mps ad0", mps);
irqs = BIT(MPS_IRQ_CMD_UPSTREAM) | BIT(MPS_IRQ_DATA_UPSTREAM)
| BIT(MPS_IRQ_DOWNLOAD_DONE) | BIT(MPS_IRQ_EVENT) | BIT(MPS_IRQ_CMD_ERROR);
__raw_writel(irqs, mps->base + MPS_REG_AD0_IRQ_ENA);
*/
return ret;
}
void mps_irq_exit(struct mps *mps)
{
free_irq(INT_NUM_IM4_IRL18, mps);
}

View file

@ -1,18 +0,0 @@
#define MPS_IRQ_BASE 160
#define MPS_IRQ(x) (MPS_IRQ_BASE + (x))
#define MPS_IRQ_CMD_UPSTREAM MPS_IRQ(0)
#define MPS_IRQ_DATA_UPSTREAM MPS_IRQ(1)
#define MPS_IRQ_CMD_DOWNSTREAM MPS_IRQ(2)
#define MPS_IRQ_DATA_DOWNSTREAM MPS_IRQ(3)
#define MPS_IRQ_RCV_OVERFLOW MPS_IRQ(4)
#define MPS_IRQ_EVENT MPS_IRQ(5)
#define MPS_IRQ_EVENT_OVERFLOW MPS_IRQ(6)
#define MPS_IRQ_CMD_ERROR MPS_IRQ(8)
#define MPS_IRQ_PCM_CRASH MPS_IRQ(9)
#define MPS_IRQ_DATA_ERROR MPS_IRQ(10)
#define MPS_IRQ_MIPS_OL MPS_IRQ(11)
#define MPS_IRQ_WATCHDOG_FAIL MPS_IRQ(14)
#define MPS_IRQ_DOWNLOAD_DONE MPS_IRQ(15)

View file

@ -1,19 +0,0 @@
int mps_message_send(struct mps_fifo *fifo, struct mps_message *msg)
{
}
int mps_message_recv(struct mps_fifo *fifo, struct mps_message *msg)
{
mps_fifo_out(fifo, &msg->header, sizeof(msg->header));
mps_fifo_out(fifo, &msg->data, mps_message_size(msg));
}
struct mps_message *msg mps_message_recv_alloc(struct mps_fifo *fifo)
{
struct mps_message *msg;
mps_fifo_out(fifo, &msg->header, sizeof(msg->header));
mps_fifo_out(fifo, &msg->data, mps_message_size(msg));
}

View file

@ -1,87 +0,0 @@
#ifndef __MPS_MSG_H__
#define __MPS_MSG_H__
#include <linux/slab.h>
struct mps_message {
uint32_t header;
uint32_t data[0];
};
#define MPS_MSG_HEADER(_rw, _sc, _bc, _cmd, _chan, _mode, _ecmd, _length) \
(((_rw) << 31) | ((_sc) << 30) | ((_bc) << 29) | ((_cmd) << 24) | \
((_chan) << 16) | ((_mode) << 13) | ((_ecmd) << 8) | (_length))
#define MPS_MSG_INIT(_msg, _rw, _sc, _bc, _cmd, _chan, _mode, _ecmd, _length) \
do { \
(_msg)->header = MPS_MSG_HEADER(_rw, _sc, _bc, _cmd, _chan, _mode, \
_ecmd, _length); \
} while(0)
static inline void mps_msg_init(struct mps_message *msg, uint32_t rw, uint32_t sc,
uint32_t bc, uint32_t cmd, uint32_t chan, uint32_t mode, uint32_t ecmd,
uint32_t length)
{
msg->header = MPS_MSG_HEADER(rw, sc, bc, cmd, chan, mode, ecmd, length);
}
#define DECLARE_MESSAGE(_name, _size) struct mps_message _name; \
uint32_t __mps_msg_data_ ## __FUNCTION__ ## __LINE__[_size]
static inline struct mps_message *mps_message_alloc(size_t size)
{
return kmalloc(sizeof(struct mps_message) + size * sizeof(uint32_t), GFP_KERNEL);
}
static inline size_t mps_message_size(const struct mps_message *msg)
{
return msg->header & 0xff;
}
enum {
MPS_MSG_WRITE = 0,
MPS_MSG_READ = 1,
};
enum {
MPS_CMD_ALI = 1,
MPS_CMD_DECT = 3,
MPS_CMD_SDD = 4,
MPS_CMD_EOP = 6,
};
#define MOD_PCM 0
#define MOD_SDD 0
#define MOD_ALI 1
#define MOD_SIGNALING 2
#define MOD_CODER 3
#define MOD_RESOURCE 6
#define MOD_SYSTEM 7
#define ECMD_SYS_VER 6
#define SYS_CAP_ECMD 7
#define ECMD_CIDS_DATA 9
#define ECMD_DCCTL_DEBUG 0x0a
#define ALI_CHAN_CMD 6
#define ALI_CHAN_ECMD 1
#define MPS_MSG_HEADER_W(_sc, _bc, _cmd, _chan, _mode, _ecmd, _length) \
MPS_MSG_HEADER(MPS_MSG_WRITE, _sc, _bc, _cmd, _chan, _mode, _ecmd, _length)
#define MPS_MSG_HEADER_R(_sc, _bc, _cmd, _chan, _mode, _ecmd, _length) \
MPS_MSG_HEADER(MPS_MSG_READ, _sc, _bc, _cmd, _chan, _mode, _ecmd, _length)
#define MPS_MSG_CMD_EOP(_mode, _ecmd, _length) \
MPS_MSG_HEADER_R(0, 0, MPS_CMD_EOP, 0, _mode, _ecmd, _length)
#define MPS_MSG_CMD_EOP_SYSTEM(_ecmd, _length) \
MPS_MSG_CMD_EOP(MOD_SYSTEM, _ecmd, _length)
#define MPS_CMD_GET_VERSION \
MPS_MSG_CMD_EOP_SYSTEM(ECMD_SYS_VER, 4)
#define MPS_CMD_ALI(_chan) \
MPS_MSG_HEADER_W(0, 0, ALI_CHAN_CMD, _chan, MOD_ALI, ALI_CHAN_ECMD, 12)
#endif

View file

@ -1,85 +0,0 @@
#ifndef __MPS_H__
#define __MPS_H__
#include <linux/platform_device.h>
#include <linux/completion.h>
struct mps_fifo_config
{
size_t head_addr;
size_t tail_addr;
size_t base_addr;
size_t size_addr;
size_t base;
size_t size;
};
struct mps_fifo {
void __iomem *base;
void __iomem *head_addr;
void __iomem *tail_addr;
uint32_t size;
};
struct mps_mailbox {
struct mps_fifo upstream;
struct mps_fifo downstream;
};
enum mps_boot_config
{
MPS_BOOT_LEGACY = 1,
MPS_BOOT_ENCRYPTED = 2,
};
struct mps {
struct resource *res;
void __iomem *base;
struct resource *mbox_res;
void __iomem *mbox_base;
struct resource *cp1_res;
void __iomem *cp1_base;
struct device *dev;
int irq_ad0;
int irq_ad1;
int irq_base;
};
void mps_configure_fifo(struct mps *mps, struct mps_fifo *fifo,
const struct mps_fifo_config *config);
void mps_configure_mailbox(struct mps *mps, struct mps_mailbox *mbox,
const struct mps_fifo_config *upstream_config,
const struct mps_fifo_config *downstream_config);
void mps_load_firmware(struct mps *mps, const void *data, size_t size,
enum mps_boot_config config);
static inline struct mps *device_to_mps(struct device *dev)
{
return (struct mps *)dev_get_drvdata(dev);
}
/* fifo */
void mps_fifo_init(struct mps_fifo *fifo, void __iomem *data_addr,
void __iomem *head_addr, void __iomem *tail_addr, uint32_t size);
void mps_fifo_in(struct mps_fifo *fifo, const uint32_t *from, size_t len);
void mps_fifo_out(struct mps_fifo *fifo, uint32_t *to, size_t len);
uint32_t mps_fifo_peek(struct mps_fifo *fifo);
void mps_fifo_reset(struct mps_fifo *fifo);
size_t mps_fifo_len(struct mps_fifo *fifo);
/* Mailbox */
int mps_mailbox_init(struct mps_mailbox *mbox, const char *name, int irq);
int mps_mailbox_command_read(struct mps_mailbox *mbox, uint32_t cmd,
uint32_t *result);
int mps_mailbox_command_write(struct mps_mailbox *mbox, uint32_t cmd,
const uint32_t *data);
#endif

View file

@ -1,129 +0,0 @@
#include <linux/kernel.h>
#include "vmmc.h"
#include "vmmc-cmds.h"
#include "vmmc-alm.h"
#include "vmmc-module.h"
#include "mps.h"
static inline struct vmmc_alm *vmmc_module_to_alm(struct vmmc_module *module)
{
return container_of(module, struct vmmc_alm, module);
}
int vmmc_alm_set_state(struct vmmc_alm *alm, enum vmmc_alm_state state)
{
int ret;
ret = vmmc_command_write(alm->vmmc, VMMC_CMD_OPMODE(alm->id), &state);
if (!ret)
alm->state = state;
return ret;
}
enum vmmc_alm_state vmmc_alm_get_state(struct vmmc_alm *alm)
{
return alm->state;
}
static struct vmmc_alm_coef *vmmc_alm_coef_alloc(unsigned int offset, size_t len)
{
struct vmmc_alm_coef *coef;
coef = kzalloc(sizeof(*coef) + sizeof(uint32_t) * DIV_ROUND_UP(len, 4),
GFP_KERNEL);
coef->offset = offset;
coef->len = len;
return coef;
}
int vmcc_alm_set_coefficents(struct vmmc_alm *alm,
const struct vmmc_alm_coef *coef_list)
{
int ret = 0;
uint32_t cmd;
struct vmmc_alm_coef *coef;
struct list_head l;
INIT_LIST_HEAD(&l);
coef = vmmc_alm_coef_alloc(0x37, 8);
coef->data[0] = 0x76d7871d;
coef->data[1] = 0x7fbb7ff4;
list_add_tail(&coef->list, &l);
coef = vmmc_alm_coef_alloc(0x5e, 2);
coef->data[0] = 0x7e000000;
list_add_tail(&coef->list, &l);
coef = vmmc_alm_coef_alloc(0x6c, 2);
coef->data[0] = 0x7e000000;
list_add_tail(&coef->list, &l);
list_for_each_entry(coef, &l, list) {
cmd = VMMC_CMD_ALM_COEF(alm->id, coef->offset, coef->len);
ret = vmmc_command_write(alm->vmmc, cmd, coef->data);
if (ret)
break;
}
return ret;
}
static int vmmc_alm_sync(struct vmmc_module *module)
{
struct vmmc_alm *alm = vmmc_module_to_alm(module);
alm->cmd_cache[0] = VMMC_CMD_ALI_DATA1(1, 0, 0, 1, 0, module->pins[0], 0x4000);
alm->cmd_cache[1] = VMMC_CMD_ALI_DATA2(0x4000, module->pins[1], module->pins[2]);
alm->cmd_cache[2] = VMMC_CMD_ALI_DATA3(module->pins[3], module->pins[4]);
return vmmc_command_write(alm->vmmc, VMMC_CMD_ALI(alm->id), alm->cmd_cache);
}
static int vmmc_alm_enable(struct vmmc_module *module, bool enable)
{
struct vmmc_alm *alm = vmmc_module_to_alm(module);
return vmmc_command_write(alm->vmmc, VMMC_CMD_ALI(alm->id), alm->cmd_cache);
}
static const struct vmmc_module_ops vmmc_alm_module_ops = {
.sync = vmmc_alm_sync,
.enable = vmmc_alm_enable,
};
int vmmc_alm_init(struct vmmc_alm *alm, struct vmmc *vmmc, unsigned int id)
{
int ret;
ret = vmmc_module_init(&alm->module, 5, &vmmc_alm_module_ops);
if (ret)
return ret;
alm->id = id;
alm->module.id = id + 0x4;
alm->vmmc = vmmc;
alm->cmd_cache[0] = VMMC_CMD_ALI_DATA1(1, 0, 0, 1, 0, 0, 0x2000);
alm->cmd_cache[1] = VMMC_CMD_ALI_DATA2(0x2000, 0, 0);
alm->cmd_cache[2] = VMMC_CMD_ALI_DATA3(0, 0);
vmmc_command_write(alm->vmmc, VMMC_CMD_ALI(alm->id), alm->cmd_cache);
vmcc_alm_set_coefficents(alm, NULL);
vmmc_register_module(vmmc, &alm->module);
// disable lec
// write lec coef
// write nlp coef
// enable lec
// ALI_LEC ALI_ES RES_LEC_COEF RES_LEC_NLP_COEF
return ret;
}
void vmmc_alm_hook_event_handler(struct vmmc *vmmc, uint32_t id, uint32_t data)
{
tapi_report_hook_event(&vmmc->tdev, &vmmc->tdev.ports[id], data & 1);
}

View file

@ -1,42 +0,0 @@
#ifndef __VMMC_ALM_H__
#define __VMMC_ALM_H__
#include "vmmc-module.h"
struct vmmc;
enum vmmc_alm_state {
VMMC_ALM_STATE_OFF = 0 << 16,
VMMC_ALM_STATE_ONHOOK = 1 << 16,
VMMC_ALM_STATE_RING = 3 << 16,
VMMC_ALM_STATE_ACTIVE = 2 << 16,
};
struct vmmc_alm {
struct vmmc *vmmc;
unsigned int id;
enum vmmc_alm_state state;
struct vmmc_module module;
uint32_t cmd_cache[3];
};
struct vmmc_alm_coef {
struct list_head list;
unsigned int offset;
size_t len;
uint32_t data[0];
};
int vmmc_alm_init(struct vmmc_alm *alm, struct vmmc *vmmc, unsigned int id);
int vmmc_alm_set_state(struct vmmc_alm *alm, enum vmmc_alm_state state);
enum vmmc_alm_state vmmc_alm_get_state(struct vmmc_alm *alm);
int vmcc_alm_set_coefficents(struct vmmc_alm *alm,
const struct vmmc_alm_coef *coef_list);
void vmmc_alm_hook_event_handler(struct vmmc *vmmc, uint32_t event, uint32_t data);
#endif

View file

@ -1,98 +0,0 @@
#ifndef __VMMC_CMDS_H__
#define __VMMC_CMDS_H__
#define _VMMC_CMD(_x) ((_x) << 24)
#define _VMMC_MOD(_x) ((_x) << 13)
#define _VMMC_ECMD(_x) ((_x) << 8)
#define _VMMC_MSG(_cmd, _mod, _ecmd) \
(_VMMC_CMD(_cmd) | _VMMC_ECMD(_ecmd) | _VMMC_MOD(_mod))
#define _VMMC_CHAN(_chan) ((_chan) << 16)
#define _VMMC_LENGTH(_length) ((_length) << 2)
#define VMMC_CMD_OPMODE(_chan) (_VMMC_MSG(1, 0, 0) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(1))
#define VMMC_CMD_SIG(_chan) (_VMMC_MSG(6, 2, 1) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(1))
#define VMMC_CMD_SIG_DATA(_enable, _event, _rate, _i1, _i2, _mute1, _mute2) \
(((_enable) << 31) | ((_event) << 30) | ((_i1) << 24) | ((_i2) << 16) | \
((_rate) << 23) | ((_mute1) << 15) | ((_mute2) << 14))
#define VMMC_CMD_SIG_SET_ENABLE(_data, _enable) (((_data) & ~BIT(31)) | ((_enable) << 31))
#define VMMC_CMD_SIG_SET_INPUTS(_data, _i1, _i2) (((_data) & ~0x3f3f0000) | \
((_i1) << 24) | ((_i2) << 16))
#define VMMC_CMD_DTMFR(_chan) (_VMMC_MSG(6, 2, 4) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(1))
#define VMMC_CMD_DTMFR_DATA(_enable, _event, _nr) \
(((_enable) << 31) | ((_event) << 30) | (6 << 27) | ((_nr) << 16))
#define VMMC_CMD_CODER(_chan) (_VMMC_MSG(6, 3, 1) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(4))
#define VMMC_CMD_CODER_DATA1(_enable, _rate, _ns, _pte, _nr, _i1, _hp, _pf, \
_cng, _bfi, _dec, _im, _pst, _sic, _em, _enc) \
(((_enable) << 31) | ((_rate) << 30) | ((_ns) << 29) | ((_pte) << 26) | \
((_nr) << 22) | ((_i1) << 16) | ((_hp) << 15) | ((_pf) << 14) | \
((_cng) << 13) | ((_bfi) << 12) | ((_dec) << 11) | ((_im) << 10) | \
((_pst) << 9) | ((_sic) << 8) | ((_em) << 7) | (_enc))
#define VMMC_CMD_CODER_DATA2(_gain1, _gain2) (((_gain1) << 16) | (_gain2))
#define VMMC_CMD_CODER_DATA3(_de, _ee, _i2, _red, _i3, _plc, _i4, _i5) \
(((_de) << 31) | ((_ee) << 30) | ((_i2) << 24) | ((_red) << 22) | \
((_i3) << 16) | ((_plc) << 15) | ((_i4) << 8) | (_i5))
#define VMMC_CMD_SERR_ACK(_chan) _VMMC_MSG(6, 7, 1) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(1)
#define VMMC_CMD_SERR_ACK_DATA1(_foo) ((_foo) << 22)
#define VMMC_CMD_CODER_DATA4(_tsf) ((_tsf) << 31)
#define VMMC_EVENT_ID_MASK (_VMMC_MSG(0x1f, 0x7, 0x1f) | 0xff)
#define VMMC_MSG_GET_CHAN(_msg) (((_msg) >> 16) & 0x1f)
#define VMMC_EVENT_HOOK_STATE(_data) ((_data) & 1)
#define VMMC_EVENT_HOOK_ID (_VMMC_MSG(9, 1, 1) | _VMMC_LENGTH(1))
#define VMMC_EVENT_DTMF_ID (_VMMC_MSG(9, 2, 0) | _VMMC_LENGTH(1))
#define VMMC_VOICE_DATA(_type, _chan, _len) (((_type) << 24) | ((_chan) << 16) \
| (_len))
#define VMMC_CMD_ALI(_chan) (_VMMC_MSG(6, 1, 1) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(3))
#define VMMC_CMD_ALI_DATA1(_enable, _rate, _ud, _eh, _eo, _i1, _dg1) \
(((_enable) << 31) | ((_rate) << 30) | ((_ud) << 29) | ((_eh) << 27) | \
((_eo) << 26) | ((_i1) << 16) | (_dg1))
#define VMMC_CMD_ALI_DATA2(_dg2, _i2, _i3) \
(((_dg2) << 16) | ((_i2) << 8) | (_i3))
#define VMMC_CMD_ALI_DATA3(_i4, _i5) \
(((_i4) << 24) | ((_i5) << 16))
#define VMMC_CMD_ALM_COEF(_chan, _offset, _len) \
(_VMMC_MSG(2, 0, _offset) | _VMMC_CHAN(_chan) | (_len))
#define CMD_VOICEREC_STATUS_PACKET 0x0
#define CMD_VOICEREC_DATA_PACKET 0x1
#define CMD_RTP_VOICE_DATA_PACKET 0x4
#define CMD_RTP_EVENT_PACKET 0x5
#define CMD_ADDRESS_PACKET 0x8
#define CMD_FAX_DATA_PACKET 0x10
#define CMD_FAX_STATUS_PACKET 0x11
#define CMD_P_PHONE_DATA_PACKET 0x12
#define CMD_P_PHONE_STATUS_PACKET 0x13
#define VMMC_CMD_RTP_CFG_US(_chan) \
(_VMMC_MSG(6, 3, 17) | _VMMC_CHAN(_chan) | (36))
#define VMMC_CMD_RTP_CFG_DS(_chan) \
(_VMMC_MSG(6, 3, 25) | _VMMC_CHAN(_chan) | (32))
#define VMMC_CMD_LEC(_chan) \
(_VMMC_MSG(6, 2, 1) | _VMMC_CHAN(_chan) | _VMMC_LENGTH(1))
// (_VMMC_MSG(CMD_EOP, ALI_LEC_ECMD, MOD_ALI) | _VMMC_CHAN(_chan) | (32))
#define VMMC_CMD_LEC_DATA()
#endif

View file

@ -1,221 +0,0 @@
#include <linux/kernel.h>
#include "vmmc.h"
#include "vmmc-cmds.h"
#include "vmmc-coder.h"
#include "vmmc-module.h"
#include "mps.h"
enum vmmc_coder_encoding {
VMMC_CODER_ENCODING_ALAW = 2,
VMMC_CODER_ENCODING_MLAW = 3,
VMMC_CODER_ENCODING_G726_16 = 4,
VMMC_CODER_ENCODING_G726_24 = 5,
VMMC_CODER_ENCODING_G726_32 = 6,
VMMC_CODER_ENCODING_G726_40 = 7,
VMMC_CODER_ENCODING_AMR_4_75 = 8,
VMMC_CODER_ENCODING_AMR_5_15 = 9,
VMMC_CODER_ENCODING_AMR_5_9 = 10,
VMMC_CODER_ENCODING_AMR_6_7 = 11,
VMMC_CODER_ENCODING_AMR_7_4 = 12,
VMMC_CODER_ENCODING_AMR_7_95 = 13,
VMMC_CODER_ENCODING_AMR_10_2 = 14,
VMMC_CODER_ENCODING_AMR_12_2 = 15,
VMMC_CODER_ENCODING_G728_16 = 16,
VMMC_CODER_ENCODING_G729AB_8 = 18,
VMMC_CODER_ENCODING_G729E_11_8 = 19,
VMMC_CODER_ENCODING_G7221_24 = 20,
VMMC_CODER_ENCODING_G7221_32 = 21,
VMMC_CODER_ENCODING_G722_64 = 22,
VMMC_CODER_ENCODING_L16_8 = 24,
VMMC_CODER_ENCODING_L16_16 = 25,
VMMC_CODER_ENCODING_ILBC_15_2 = 26,
VMMC_CODER_ENCODING_ILBC_13_3 = 27,
VMMC_CODER_ENCODING_G7231_5_3 = 28,
VMMC_CODER_ENCODING_G7231_6_3 = 29,
VMMC_CODER_ENCODING_ALAW_VBD = 30,
VMMC_CODER_ENCODING_MLAW_VBD = 31,
};
static const uint8_t vmmc_coder_payload_mapping[] = {
[VMMC_CODER_ENCODING_ALAW] = 8,
[VMMC_CODER_ENCODING_MLAW] = 0,
[VMMC_CODER_ENCODING_G726_16] = 35,
[VMMC_CODER_ENCODING_G726_24] = 36,
[VMMC_CODER_ENCODING_G726_32] = 37,
[VMMC_CODER_ENCODING_G726_40] = 38,
[VMMC_CODER_ENCODING_AMR_4_75] = 39,
[VMMC_CODER_ENCODING_AMR_5_15] = 40,
[VMMC_CODER_ENCODING_AMR_5_9] = 41,
[VMMC_CODER_ENCODING_AMR_6_7] = 42,
[VMMC_CODER_ENCODING_AMR_7_4] = 43,
[VMMC_CODER_ENCODING_AMR_7_95] = 44,
[VMMC_CODER_ENCODING_AMR_10_2] = 45,
[VMMC_CODER_ENCODING_AMR_12_2] = 46,
[VMMC_CODER_ENCODING_G728_16] = 47,
[VMMC_CODER_ENCODING_G729AB_8] = 48,
[VMMC_CODER_ENCODING_G729E_11_8] = 49,
[VMMC_CODER_ENCODING_G7221_24] = 50,
[VMMC_CODER_ENCODING_G7221_32] = 51,
[VMMC_CODER_ENCODING_G722_64] = 52,
[VMMC_CODER_ENCODING_L16_8] = 11,
[VMMC_CODER_ENCODING_L16_16] = 10,
[VMMC_CODER_ENCODING_ILBC_15_2] = 53,
[VMMC_CODER_ENCODING_ILBC_13_3] = 54,
[VMMC_CODER_ENCODING_G7231_5_3] = 4,
[VMMC_CODER_ENCODING_G7231_6_3] = 4,
[VMMC_CODER_ENCODING_ALAW_VBD] = 55,
[VMMC_CODER_ENCODING_MLAW_VBD] = 56,
};
static uint32_t payload_enc[9];
static uint32_t payload_dec[8];
static inline struct vmmc_coder *vmmc_module_to_coder(struct vmmc_module *module)
{
return container_of(module, struct vmmc_coder, module);
}
static int vmmc_coder_enable(struct vmmc_module *module, bool enable)
{
struct vmmc_coder *coder = vmmc_module_to_coder(module);
coder->enabled = enable;
/* coder->cmd_cache[0] = VMMC_CMD_CODER_DATA1(coder->enabled, 0, 0, 0, coder->id,
module->pins[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
return vmmc_command_write(coder->vmmc, VMMC_CMD_CODER(coder->id),
coder->cmd_cache);*/
return 0;
}
static int vmmc_coder_sync(struct vmmc_module *module)
{
struct vmmc_coder *coder = vmmc_module_to_coder(module);
coder->cmd_cache[0] = VMMC_CMD_CODER_DATA1(coder->enabled, 0, 1, 1, coder->id,
module->pins[0], 1, 1, 1, 1, 1, 1, 0, 0, 0, VMMC_CODER_ENCODING_MLAW);
coder->cmd_cache[1] = VMMC_CMD_CODER_DATA2(0x2000, 0x2000);
coder->cmd_cache[2] = VMMC_CMD_CODER_DATA3(0, 0, module->pins[1], 0,
module->pins[2], 0, module->pins[3], module->pins[4]);
return vmmc_command_write(coder->vmmc, VMMC_CMD_CODER(coder->id), coder->cmd_cache);
}
static const struct vmmc_module_ops vmmc_coder_module_ops = {
.sync = vmmc_coder_sync,
.enable = vmmc_coder_enable,
};
#define VMMC_CMD_CODER_JB(_chan) (_VMMC_MSG(6, 3, 18) | _VMMC_CHAN(_chan) | 8)
#define VMMC_CMD_CODER_JB_DATA1(_sf, _prp, _pje, _dvf, _nam, _rad, _adap, _init_pod) \
(((_sf) << 31) | ((_prp) << 23) | ((_pje) << 22) | ((_dvf) << 21) | \
((_nam) << 20) | ((_rad) << 17) | ((_adap) << 16) | (_init_pod))
#define VMMC_CMD_CODER_JB_DATA2(_min_pod, _max_pod) \
(((_min_pod) << 16) | (_max_pod))
#define VMMC_CMD_CODER_JB_DATA3(_adap_factor, _min_margin, _mode) \
(((_adap_factor) << 24) | ((_min_margin) << 16) | (_mode))
int vmmc_coder_init(struct vmmc_coder *coder, struct vmmc *vmmc, unsigned int id)
{
int ret;
ret = vmmc_module_init(&coder->module, 5, &vmmc_coder_module_ops);
if (ret)
return ret;
coder->id = id;
coder->module.id = id + 0x18;
coder->vmmc = vmmc;
coder->enabled = 0;
coder->cmd_cache[0] = VMMC_CMD_CODER_DATA1(0, 0, 0, 0, id, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
coder->cmd_cache[1] = VMMC_CMD_CODER_DATA2(0, 0);
coder->cmd_cache[2] = VMMC_CMD_CODER_DATA3(0, 0, 0, 0, 0, 0, 0, 0);
coder->cmd_cache[3] = VMMC_CMD_CODER_DATA4(0);
coder->jitter_buffer_cache[0] = VMMC_CMD_CODER_JB_DATA1(0x16, 1, 0, 0, 1, 1,
1, 0x50);
coder->jitter_buffer_cache[1] = VMMC_CMD_CODER_JB_DATA2(0x50, 0x05a0);
coder->jitter_buffer_cache[2] = VMMC_CMD_CODER_JB_DATA3(0x0d, 0x28, 1);
vmmc_command_write(coder->vmmc, VMMC_CMD_RTP_CFG_US(coder->id), payload_enc);
vmmc_command_write(coder->vmmc, VMMC_CMD_RTP_CFG_DS(coder->id), payload_dec);
vmmc_command_write(coder->vmmc, VMMC_CMD_CODER_JB(coder->id),
coder->jitter_buffer_cache);
vmmc_command_write(coder->vmmc, VMMC_CMD_CODER(coder->id), coder->cmd_cache);
vmmc_register_module(vmmc, &coder->module);
return ret;
}
void vmmc_coder_event(struct vmmc *vmmc, unsigned int chan, unsigned int type)
{
}
/*
void vmmc_coder_event(struct vmmc_coder *coder, unsigned int len)
{
struct sk_buff *skb;
provide_mem_region(coder->vmmc, vmmc_coder_alloc_paket(coder)->head, 512);
skb = skb_dequeue(&coder->paket_queue);
skb_put(skb, len);
tapi_stream_recv(&coder->vmmc->tdev, skb);
}
*/
/*
int vmmc_coder_set_codec(struct vmmc_coder *coder, enum vmmc_codec codec)
{
}*/
void vmmc_init_coders(struct vmmc *vmmc)
{
unsigned int i;
payload_enc[0] = 0;
payload_enc[1] = 0x0;
payload_enc[1] |= vmmc_coder_payload_mapping[2] << 8;
payload_enc[1] |= vmmc_coder_payload_mapping[3] << 8;
for (i = 2; i < 9; ++i) {
payload_enc[i] = vmmc_coder_payload_mapping[i*4 - 4] << 24;
payload_enc[i] |= vmmc_coder_payload_mapping[i*4 - 3] << 16;
payload_enc[i] |= vmmc_coder_payload_mapping[i*4 - 2] << 8;
payload_enc[i] |= vmmc_coder_payload_mapping[i*4 - 1];
payload_enc[i] |= 0x80808080;
}
for (i = 0; i < 7; ++i) {
payload_dec[i] = vmmc_coder_payload_mapping[i*4 + 2] << 24;
payload_dec[i] |= vmmc_coder_payload_mapping[i*4 + 3] << 16;
payload_dec[i] |= vmmc_coder_payload_mapping[i*4 + 4] << 8;
payload_dec[i] |= vmmc_coder_payload_mapping[i*4 + 5];
}
payload_dec[i] = vmmc_coder_payload_mapping[i*4 + 2] << 24;
payload_dec[i] |= vmmc_coder_payload_mapping[i*4 + 3] << 16;
vmmc->num_coders = 5;
vmmc->coder = kcalloc(sizeof(*vmmc->coder), vmmc->num_coders, GFP_KERNEL);
for (i = 0; i < vmmc->num_coders; ++i)
vmmc_coder_init(&vmmc->coder[i], vmmc, i);
}
struct vmmc_coder *vmmc_coder_get(struct vmmc *vmmc)
{
unsigned int i;
for (i = 0; i < vmmc->num_coders; ++i) {
if (!test_and_set_bit(i, &vmmc->coder_used))
return &vmmc->coder[i];
}
return NULL;
}
void vmmc_coder_put(struct vmmc *vmmc, struct vmmc_coder *coder)
{
clear_bit(coder->id, &vmmc->coder_used);
}

View file

@ -1,14 +0,0 @@
struct vmmc_coder {
struct vmmc *vmmc;
unsigned int id;
struct vmmc_module module;
unsigned int enabled;
uint32_t cmd_cache[4];
uint32_t jitter_buffer_cache[3];
struct tapi_stream *stream;
};

View file

@ -1,646 +0,0 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <ifxmips_gptu.h>
#include <linux/tapi/tapi.h>
#include "vmmc.h"
#include "mps.h"
#include "mps-msg.h"
#include "mps-irq.h"
#include "vmmc-cmds.h"
#include "vmmc-port.h"
#include "vmmc-stream.h"
#include "vmmc-link.h"
#include "vmmc-coder.h"
struct vmmc_capabilities {
uint8_t num_alm;
uint8_t num_pcm;
uint8_t num_signal;
uint8_t num_coder;
uint8_t num_agc;
uint8_t num_eq;
uint8_t num_nlec;
uint8_t num_wlec;
uint8_t num_nwlec;
uint8_t num_wwlec;
uint8_t num_tone_generators;
uint8_t num_dtmf_generators;
uint8_t num_caller_id_senders;
uint8_t num_caller_id_recivers;
};
#define MPS_FIRMWARE_MAGIC 0xcc123456
struct vmmc_firmware_head {
uint32_t crc;
uint32_t crc_start_addr;
uint32_t crc_end_addr;
uint32_t version;
uint32_t encrypted;
uint32_t magic;
uint32_t mem;
} __packed;
#define VMMC_FIFO_UPSTREAM_CMD_BASE_ADDR 0x00
#define VMMC_FIFO_UPSTREAM_CMD_SIZE_ADDR 0x04
#define VMMC_FIFO_DOWNSTREAM_CMD_BASE_ADDR 0x08
#define VMMC_FIFO_DOWNSTREAM_CMD_SIZE_ADDR 0x0c
#define VMMC_FIFO_UPSTREAM_DATA_BASE_ADDR 0x10
#define VMMC_FIFO_UPSTREAM_DATA_SIZE_ADDR 0x14
#define VMMC_FIFO_DOWNSTREAM_DATA_BASE_ADDR 0x18
#define VMMC_FIFO_DOWNSTREAM_DATA_SIZE_ADDR 0x1c
#define VMMC_FIFO_UPSTREAM_CMD_TAIL_ADDR 0x20
#define VMMC_FIFO_UPSTREAM_CMD_HEAD_ADDR 0x24
#define VMMC_FIFO_DOWNSTREAM_CMD_TAIL_ADDR 0x28
#define VMMC_FIFO_DOWNSTREAM_CMD_HEAD_ADDR 0x2c
#define VMMC_FIFO_UPSTREAM_DATA_TAIL_ADDR 0x30
#define VMMC_FIFO_UPSTREAM_DATA_HEAD_ADDR 0x34
#define VMMC_FIFO_DOWNSTREAM_DATA_TAIL_ADDR 0x38
#define VMMC_FIFO_DOWNSTREAM_DATA_HEAD_ADDR 0x3c
#define VMMC_FIFO_EVENT_BASE_ADDR 0x180
#define VMMC_FIFO_EVENT_SIZE_ADDR 0x184
#define VMMC_FIFO_EVENT_TAIL_ADDR 0x188
#define VMMC_FIFO_EVENT_HEAD_ADDR 0x18c
/* Calculates the base of the fifo behind the given fifo */
#define VMMC_NEXT_FIFO_BASE0(_fifo) \
(VMMC_FIFO_ ## _fifo ## _BASE + VMMC_FIFO_ ## _fifo ## _SIZE)
#define VMMC_NEXT_FIFO_BASE1(_fifo) \
(VMMC_FIFO_ ## _fifo ## _BASE + VMMC_FIFO_ ## _fifo ## _SIZE)
#define VMMC_NEXT_FIFO_BASE2(_fifo) \
(VMMC_FIFO_ ## _fifo ## _BASE + VMMC_FIFO_ ## _fifo ## _SIZE)
/* Fifo sizes */
#define VMMC_FIFO_UPSTREAM_CMD_SIZE 64
#define VMMC_FIFO_DOWNSTREAM_CMD_SIZE 64
#define VMMC_FIFO_UPSTREAM_DATA_SIZE 64
#define VMMC_FIFO_DOWNSTREAM_DATA_SIZE 128
#define VMMC_FIFO_EVENT_SIZE 64
/* Fifo addresses */
#define VMMC_FIFO_UPSTREAM_CMD_BASE 0x40
#define VMMC_FIFO_DOWNSTREAM_CMD_BASE VMMC_NEXT_FIFO_BASE0(UPSTREAM_CMD)
#define VMMC_FIFO_UPSTREAM_DATA_BASE VMMC_NEXT_FIFO_BASE1(DOWNSTREAM_CMD)
#define VMMC_FIFO_DOWNSTREAM_DATA_BASE VMMC_NEXT_FIFO_BASE2(UPSTREAM_DATA)
#define VMMC_FIFO_EVENT_BASE 0x190
#define VMMC_DECLARE_FIFO_CONFIG(_name, _fifo) \
static const struct mps_fifo_config _name = { \
.tail_addr = VMMC_FIFO_ ## _fifo ## _TAIL_ADDR, \
.head_addr = VMMC_FIFO_ ## _fifo ## _HEAD_ADDR, \
.base_addr = VMMC_FIFO_ ## _fifo ## _BASE_ADDR, \
.size_addr = VMMC_FIFO_ ## _fifo ## _SIZE_ADDR, \
.base = VMMC_FIFO_ ## _fifo ## _BASE, \
.size = VMMC_FIFO_ ## _fifo ## _SIZE, \
}
VMMC_DECLARE_FIFO_CONFIG(vmmc_fifo_config_upstream_cmd, UPSTREAM_CMD);
VMMC_DECLARE_FIFO_CONFIG(vmmc_fifo_config_downstream_cmd, DOWNSTREAM_CMD);
VMMC_DECLARE_FIFO_CONFIG(vmmc_fifo_config_upstream_data, UPSTREAM_DATA);
VMMC_DECLARE_FIFO_CONFIG(vmmc_fifo_config_downstream_data, DOWNSTREAM_DATA);
VMMC_DECLARE_FIFO_CONFIG(vmmc_fifo_config_event, EVENT);
static void vmmc_setup_fifos(struct vmmc *vmmc)
{
mps_configure_mailbox(vmmc->mps, &vmmc->mbox_cmd,
&vmmc_fifo_config_upstream_cmd, &vmmc_fifo_config_downstream_cmd);
mps_configure_mailbox(vmmc->mps, &vmmc->mbox_data,
&vmmc_fifo_config_upstream_data, &vmmc_fifo_config_downstream_data);
mps_configure_fifo(vmmc->mps, &vmmc->fifo_event, &vmmc_fifo_config_event);
}
static uint32_t cram_data[] = {
0x00200000, 0x00008e59, 0x165235cd, 0x17e2f141, 0xe3eef301, 0x0a431281,
0x04fdf20d, 0x7fe363d5, 0xfd4b7333, 0x7ffffd44, 0xfcf80298, 0xfecd00c9,
0xff900042, 0xfff70003, 0x000923b7, 0xe92a354d, 0xc8981f44, 0x9c0f1257,
0x26aacf33, 0x27db9836, 0x10586f5b, 0x9c167d2d, 0x94b679a7, 0x8c227660,
0x83fa7491, 0x7ce0826a, 0x7ff87ff4, 0x296b4e22, 0x76e67fff, 0x008ffc04,
0x02cbfb36, 0x026afeba, 0x009effc3, 0x0013fffd, 0x23b7e92a, 0x354dc898,
0x1f449c0f, 0x125726aa, 0xcf3327db, 0x98361058, 0x74bc93d6, 0x7ebc8f61,
0x7d068986, 0x7b46833b, 0x7a3b7f00, 0x287a47b1, 0x05800367, 0x20ae2715,
0x0fb5da12, 0x1935f53b, 0x01230240, 0xfc717f00, 0x2000d346,
};
static void vmmc_push_data_paket(struct vmmc *vmmc, int type, unsigned int chan,
void __iomem *addr, size_t len)
{
uint32_t data[3];
data[0] = VMMC_VOICE_DATA(type, chan, 8);
data[1] = CPHYSADDR(addr);
data[2] = len;
mps_fifo_in(&vmmc->mbox_data.downstream, data, 3);
}
static struct sk_buff *vmmc_alloc_data_paket(struct vmmc *vmmc)
{
struct sk_buff *skb;
skb = alloc_skb(512, GFP_KERNEL);
skb_queue_tail(&vmmc->recv_queue, skb);
return skb;
}
static void vmmc_provide_paket(struct vmmc *vmmc)
{
struct sk_buff *skb = vmmc_alloc_data_paket(vmmc);
vmmc_push_data_paket(vmmc, CMD_ADDRESS_PACKET, 0, skb->data, skb->len);
}
static void vmmc_recv_paket(struct vmmc *vmmc, unsigned int chan, void __iomem *addr, size_t len)
{
struct sk_buff *skb;
struct sk_buff *tmp;
skb_queue_walk_safe(&vmmc->recv_queue, skb, tmp) {
if (skb->data == addr)
break;
}
if (skb == (struct sk_buff *)(&vmmc->recv_queue)) {
printk("AHHHH\n");
return;
}
dma_cache_inv((u32)addr, len);
skb_unlink(skb, &vmmc->recv_queue);
if (!vmmc->coder[chan].stream) {
kfree_skb(skb);
return;
}
skb_put(skb, len);
tapi_stream_recv(&vmmc->tdev, vmmc->coder[chan].stream, skb);
}
void vmmc_send_paket(struct vmmc *vmmc, unsigned int chan, struct sk_buff *skb)
{
skb_queue_tail(&vmmc->send_queue, skb);
dma_cache_wback((u32)skb->data, skb->len);
vmmc_push_data_paket(vmmc, CMD_RTP_VOICE_DATA_PACKET, chan, skb->data,
skb->len);
}
static void vmmc_free_paket(struct vmmc *vmmc, void __iomem *addr, size_t len)
{
struct sk_buff *skb;
struct sk_buff *tmp;
skb_queue_walk_safe(&vmmc->send_queue, skb, tmp) {
if (skb->data == addr)
break;
}
if (skb == (struct sk_buff *)(&vmmc->send_queue)) {
printk("AHHHH\n");
} else {
skb_unlink(skb, &vmmc->send_queue);
kfree_skb(skb);
}
}
static void vmmc_write_cram_data(struct vmmc *vmmc, unsigned int id,
uint32_t *data, size_t length)
{
size_t transfer_length;
size_t offset = 0;
uint32_t cmd;
length *= 4;
offset = 0x5;
while (length) {
transfer_length = length > 56 ? 56 : length;
cmd = VMMC_CMD_ALM_COEF(id, offset, transfer_length);
vmmc_command_write(vmmc, cmd, data);
data += transfer_length >> 2;
offset += transfer_length >> 1;
length -= transfer_length;
}
}
int vmmc_command_read(struct vmmc *vmmc, uint32_t cmd, uint32_t *result)
{
struct mps_mailbox *mbox = &vmmc->mbox_cmd;
INIT_COMPLETION(vmmc->cmd_completion);
mps_fifo_in(&mbox->downstream, &cmd, 1);
wait_for_completion(&vmmc->cmd_completion);
mps_fifo_out(&mbox->upstream, result, 1);
mps_fifo_out(&mbox->upstream, result, (*result & 0xff) / 4);
return 0;
}
int vmmc_command_write(struct vmmc *vmmc, uint32_t cmd,
const uint32_t *data)
{
struct mps_mailbox *mbox = &vmmc->mbox_cmd;
/* int i;
printk("cmd: %x\n", cmd);
for (i = 0; i < DIV_ROUND_UP((cmd & 0xff), 4); ++i) {
printk("data[%d] = %x\n", i, data[i]);
}
*/
while (mps_fifo_len(&mbox->downstream) < (cmd & 0xff) + 4)
mdelay(100);
mps_fifo_in(&mbox->downstream, &cmd, 1);
mps_fifo_in(&mbox->downstream, data, DIV_ROUND_UP((cmd & 0xff), 4));
mdelay(100);
return 0;
}
static int vmmc_modules_sync(struct tapi_device *tapi)
{
struct vmmc *vmmc = tdev_to_vmmc(tapi);
struct vmmc_module *module;
list_for_each_entry(module, &vmmc->modules, head)
vmmc_module_sync(module);
return 0;
}
static const struct tapi_ops vmmc_tapi_ops = {
.send_dtmf_event = vmmc_port_send_dtmf_event,
.ring = vmmc_port_ring,
.sync = vmmc_modules_sync,
.stream_alloc = vmmc_stream_alloc,
.stream_free = vmmc_stream_free,
.stream_send = vmmc_stream_send,
.link_alloc = vmmc_tapi_link_alloc,
.link_free = vmmc_tapi_link_free,
.link_enable = vmmc_tapi_link_enable,
.link_disable = vmmc_tapi_link_disable,
};
static void setup_alm(struct vmmc *vmmc)
{
int i;
vmmc->tdev.ports = kcalloc(2, sizeof(*vmmc->tdev.ports), GFP_KERNEL);
vmmc->ports = kcalloc(2, sizeof(*vmmc->ports), GFP_KERNEL);
for (i = 0; i < 2; ++i)
vmmc_port_init(vmmc, &vmmc->ports[i], &vmmc->tdev.ports[i], i);
skb_queue_head_init(&vmmc->send_queue);
skb_queue_head_init(&vmmc->recv_queue);
for (i = 0; i < 10; ++i)
vmmc_provide_paket(vmmc);
vmmc->tdev.num_ports = 2;
vmmc->tdev.ops = &vmmc_tapi_ops;
tapi_device_register(&vmmc->tdev, "vmmc", vmmc->dev);
}
static void vmmc_init_timer(struct vmmc *vmmc)
{
unsigned int timer;
unsigned int timer_flags;
int ret;
unsigned long loops, count;
timer = TIMER1B;
timer_flags =
TIMER_FLAG_16BIT | TIMER_FLAG_COUNTER | TIMER_FLAG_CYCLIC |
TIMER_FLAG_DOWN | TIMER_FLAG_FALL_EDGE | TIMER_FLAG_SYNC |
TIMER_FLAG_CALLBACK_IN_IRQ;
ret = ifxmips_request_timer (timer, timer_flags, 1, 0, 0);
if (ret < 0) {
printk("FAILED TO INIT TIMER\n");
return;
}
ret = ifxmips_start_timer (timer, 0);
if (ret < 0) {
printk("FAILED TO START TIMER\n");
return;
}
do
{
loops++;
ifxmips_get_count_value(timer, &count);
} while (count);
*((volatile uint32_t *) (KSEG1 + 0x1e100a00 + 0x0014)) = 0x000005c5;
}
static void vmmc_free_timer(struct vmmc *vmmc)
{
ifxmips_free_timer(TIMER1B);
}
static void vmmc_get_capabilities(struct vmmc *vmmc)
{
uint32_t data[10];
uint8_t len;
vmmc_command_read(vmmc,
MPS_MSG_CMD_EOP_SYSTEM(SYS_CAP_ECMD, sizeof(uint32_t)), data);
len = ((data[0] >> 16) & 0xff) - sizeof(uint32_t);
if (len > sizeof(data))
len = sizeof(data);
vmmc_command_read(vmmc,
MPS_MSG_CMD_EOP_SYSTEM(SYS_CAP_ECMD, len), data);
len /= 4;
/* for (;len > 0; --len) {
printk("fw cap(%d): %.2x\n", 10-len, data[10-len]);
}
*/
setup_alm(vmmc);
}
static void vmmc_get_firmware_version(struct vmmc *vmmc)
{
uint32_t data[1];
vmmc_command_read(vmmc, MPS_CMD_GET_VERSION, data);
printk("firmware version: %x\n", *data);
vmmc_get_capabilities(vmmc);
}
static irqreturn_t vmmc_firmware_loaded_irq(int irq, void *devid)
{
struct vmmc *vmmc = devid;
complete(&vmmc->firmware_loaded_completion);
printk("Firmware loaded irq\n");
return IRQ_HANDLED;
}
static irqreturn_t vmmc_cmd_error_irq(int irq, void *devid)
{
/* struct vmmc *vmmc = devid;*/
printk("cmd error!!!!\n");
return IRQ_HANDLED;
}
static irqreturn_t vmmc_recv_ov_irq(int irq, void *devid)
{
struct vmmc *vmmc = devid;
uint32_t data[2] = {
VMMC_CMD_SERR_ACK(0),
VMMC_CMD_SERR_ACK_DATA1(1)
};
uint32_t voice_data[64];
return IRQ_HANDLED;
mps_fifo_in(&vmmc->mbox_cmd.downstream, data, 2);
mps_fifo_out(&vmmc->mbox_data.upstream, voice_data, 15);
printk("recv overflow: %x\n", voice_data[0]);
return IRQ_HANDLED;
}
static irqreturn_t vmmc_event_fifo_irq(int irq, void *devid)
{
struct vmmc *vmmc = devid;
uint32_t event, event_id;
uint32_t data = 0;
unsigned int chan;
mps_fifo_out(&vmmc->fifo_event, &event, 1);
event_id = event & VMMC_EVENT_ID_MASK;
chan = VMMC_MSG_GET_CHAN(event);
if (event & 0xff)
mps_fifo_out(&vmmc->fifo_event, &data, 1);
switch (event_id) {
case VMMC_EVENT_HOOK_ID:
vmmc_alm_hook_event_handler(vmmc, chan, data);
break;
case VMMC_EVENT_DTMF_ID:
vmmc_sig_dtmf_event_handler(vmmc, chan, data);
break;
default:
printk("Ein unbekanntes Event: %x %x\n", event, data);
break;
}
return IRQ_HANDLED;
}
static irqreturn_t vmmc_mbox_data_irq_handler(int irq, void *devid)
{
struct vmmc *vmmc = devid;
struct mps_mailbox *mbox = &vmmc->mbox_data;
unsigned int count, type, chan;
uint32_t data[2];
void __iomem *addr;
size_t len;
mps_fifo_out(&mbox->upstream, data, 1);
count = (data[0] & 0xff) / 8;
type = (data[0] >> 24) & 0xff;
chan = (data[0] >> 16) & 0xff;
while (count) {
mps_fifo_out(&mbox->upstream, data, 2);
addr = (void __iomem *)CKSEG0ADDR(data[0]);
len = data[1];
switch (type) {
case CMD_ADDRESS_PACKET:
vmmc_free_paket(vmmc, addr, len);
break;
case CMD_RTP_VOICE_DATA_PACKET:
vmmc_provide_paket(vmmc);
vmmc_recv_paket(vmmc, chan, addr, len);
break;
}
--count;
}
return IRQ_HANDLED;
}
static irqreturn_t vmmc_mbox_cmd_irq_handler(int irq, void *devid)
{
struct vmmc *vmmc = devid;
complete(&vmmc->cmd_completion);
return IRQ_HANDLED;
}
static void vmmc_load_firmware(const struct firmware *fw, void *context)
{
struct vmmc *vmmc = context;
struct vmmc_firmware_head *fw_head;
size_t tail_size;
enum mps_boot_config config;
if (!fw) {
printk("failed to load tapi firmware\n");
// request_firmware_nowait(THIS_MODULE, 1, "danube_firmware.bin", vmmc->dev,
// GFP_KERNEL, vmmc, vmmc_load_firmware);
return;
}
if (fw->size < sizeof(*fw_head))
return;
fw_head = (struct vmmc_firmware_head *)((uint8_t *)fw->data + fw->size - sizeof(*fw_head));
if (fw_head->magic != MPS_FIRMWARE_MAGIC) {
config = MPS_BOOT_LEGACY;
tail_size = sizeof(uint32_t);
} else {
config = MPS_BOOT_ENCRYPTED;
tail_size = sizeof(*fw_head) - sizeof(uint32_t);
}
vmmc_setup_fifos(vmmc);
init_completion(&vmmc->firmware_loaded_completion);
mps_load_firmware(vmmc->mps, fw->data, fw->size - tail_size, config);
wait_for_completion_timeout(&vmmc->firmware_loaded_completion, 5*HZ);
vmmc_init_timer(vmmc);
vmmc_write_cram_data(vmmc, 0, cram_data, ARRAY_SIZE(cram_data));
vmmc_write_cram_data(vmmc, 1, cram_data, ARRAY_SIZE(cram_data));
vmmc_get_firmware_version(vmmc);
vmmc_init_coders(vmmc);
}
static int vmmc_request_irqs(struct vmmc *vmmc)
{
int ret;
ret = request_irq(vmmc->irq_fw_loaded, vmmc_firmware_loaded_irq, 0, "vmmc fw loaded", vmmc);
ret = request_irq(vmmc->irq_event_fifo, vmmc_event_fifo_irq, 0, "vmmc event fifo", vmmc);
ret = request_irq(vmmc->irq_cmd_error, vmmc_cmd_error_irq, 0,
"cmd error irq", vmmc);
ret = request_irq(MPS_IRQ_RCV_OVERFLOW, vmmc_recv_ov_irq, 0,
"recv_ov irq", vmmc);
ret = request_irq(vmmc->irq_mbox_cmd, vmmc_mbox_cmd_irq_handler, 0,
"vmmc cmd mailbox irq", vmmc);
ret = request_irq(vmmc->irq_mbox_data, vmmc_mbox_data_irq_handler, 0,
"vmmc data mailbox irq", vmmc);
return ret;
}
static int __devinit vmmc_probe(struct platform_device *pdev)
{
struct vmmc *vmmc;
int ret = 0;
vmmc = kzalloc(sizeof(*vmmc), GFP_KERNEL);
if (!vmmc)
return -ENOMEM;
vmmc->dev = &pdev->dev;
vmmc->mps = device_to_mps(pdev->dev.parent);
if (!vmmc->mps) {
goto err_free;
ret = -EBUSY;
}
INIT_LIST_HEAD(&vmmc->modules);
init_completion(&vmmc->cmd_completion);
vmmc->irq_fw_loaded = MPS_IRQ_DOWNLOAD_DONE;
vmmc->irq_mbox_cmd = MPS_IRQ_CMD_UPSTREAM;
vmmc->irq_mbox_data = MPS_IRQ_DATA_UPSTREAM;
vmmc->irq_event_fifo = MPS_IRQ_EVENT;
vmmc->irq_cmd_error = MPS_IRQ_CMD_ERROR;
platform_set_drvdata(pdev, vmmc);
vmmc_request_irqs(vmmc);
request_firmware_nowait(THIS_MODULE, 1, "danube_firmware.bin", &pdev->dev,
GFP_KERNEL, vmmc, vmmc_load_firmware);
return 0;
err_free:
kfree(vmmc);
return ret;
}
static int __devexit vmmc_remove(struct platform_device *pdev)
{
struct vmmc *vmmc = platform_get_drvdata(pdev);
vmmc_free_timer(vmmc);
tapi_device_unregister(&vmmc->tdev);
return 0;
}
static struct platform_driver vmmc_driver = {
.probe = vmmc_probe,
.remove = __devexit_p(vmmc_remove),
.driver = {
.name = "vmmc",
.owner = THIS_MODULE
},
};
static int __init vmmc_init(void)
{
return platform_driver_register(&vmmc_driver);
}
module_init(vmmc_init);
static void __exit vmmc_exit(void)
{
platform_driver_unregister(&vmmc_driver);
}
module_exit(vmmc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");

View file

@ -1,52 +0,0 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/tapi/tapi.h>
#include "vmmc-link.h"
#include "vmmc-module.h"
struct vmmc_tapi_link {
struct tapi_link tapi_link;
struct vmmc_link vmmc_link;
};
struct tapi_link *vmmc_tapi_link_alloc(struct tapi_device *tdev,
struct tapi_endpoint *ep1, struct tapi_endpoint *ep2)
{
struct vmmc_tapi_link *link = kzalloc(sizeof(*link), GFP_KERNEL);
struct vmmc_module *module1 = tapi_endpoint_to_vmmc_module(ep1);
struct vmmc_module *module2 = tapi_endpoint_to_vmmc_module(ep2);
vmmc_link_init(&link->vmmc_link, module1, module2);
return &link->tapi_link;
}
void vmmc_tapi_link_free(struct tapi_device *tdev, struct tapi_link *tapi_link)
{
struct vmmc_tapi_link *link = container_of(tapi_link, struct vmmc_tapi_link,
tapi_link);
vmmc_link_put(&link->vmmc_link);
kfree(link);
}
int vmmc_tapi_link_enable(struct tapi_device *tdev,
struct tapi_link *tapi_link)
{
struct vmmc_tapi_link *link = container_of(tapi_link, struct vmmc_tapi_link,
tapi_link);
vmmc_link_enable(&link->vmmc_link);
return 0;
}
int vmmc_tapi_link_disable(struct tapi_device *tdev,
struct tapi_link *tapi_link)
{
struct vmmc_tapi_link *link = container_of(tapi_link, struct vmmc_tapi_link,
tapi_link);
vmmc_link_disable(&link->vmmc_link);
return 0;
}

View file

@ -1,10 +0,0 @@
#ifndef __VMMC_LINK_H__
#define __VMMC_LINK_H__
struct tapi_link *vmmc_tapi_link_alloc(struct tapi_device *tdev,
struct tapi_endpoint *ep1, struct tapi_endpoint *ep2);
void vmmc_tapi_link_free(struct tapi_device *tdev, struct tapi_link *link);
int vmmc_tapi_link_enable(struct tapi_device *tdev, struct tapi_link *link);
int vmmc_tapi_link_disable(struct tapi_device *tdev, struct tapi_link *link);
#endif

View file

@ -1,130 +0,0 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <asm/bitops.h>
#include "vmmc-module.h"
int vmmc_module_init(struct vmmc_module *module, size_t num_pins,
const struct vmmc_module_ops *ops)
{
module->pins = kcalloc(num_pins, sizeof(*module->pins), GFP_KERNEL);
if (!module->pins)
return -ENOMEM;
module->num_pins = num_pins;
module->ops = ops;
mutex_init(&module->lock);
module->refcount = 0;
return 0;
}
int vmmc_module_sync(struct vmmc_module *module)
{
if (!test_and_clear_bit(VMMC_MODULE_FLAG_MODIFIED, &module->flags))
return 0;
return module->ops->sync(module);
}
int vmmc_module_get_pin(struct vmmc_module *module)
{
size_t i = 0;
int ret = 0;
for (i = 0; i < module->num_pins; ++i) {
if (!test_and_set_bit(VMMC_MODULE_FLAG_PIN_USED(i), &module->flags))
break;
}
if (i == module->num_pins)
ret = -EBUSY;
else
ret = i;
return ret;
}
void vmmc_module_put_pin(struct vmmc_module *module, unsigned int pin)
{
module->pins[pin] = 0;
clear_bit(VMMC_MODULE_FLAG_PIN_USED(pin), &module->flags);
}
void vmmc_module_set_pin_input(struct vmmc_module *module, unsigned int pin,
struct vmmc_module *input)
{
if (input)
module->pins[pin] = input->id;
else
module->pins[pin] = 0;
set_bit(VMMC_MODULE_FLAG_MODIFIED, &module->flags);
}
static void vmmc_module_enable(struct vmmc_module *module)
{
mutex_lock(&module->lock);
if (++module->refcount == 1)
module->ops->enable(module, true);
mutex_unlock(&module->lock);
}
static void vmmc_module_disable(struct vmmc_module *module)
{
mutex_lock(&module->lock);
if (module->refcount <= 0)
printk(KERN_ERR "vmmc module: unbalanced disable\n");
else if (--module->refcount == 0)
module->ops->enable(module, false);
mutex_unlock(&module->lock);
}
unsigned int vmmc_link_init(struct vmmc_link *link,
struct vmmc_module *a, struct vmmc_module *b)
{
link->pins[0] = vmmc_module_get_pin(a);
link->pins[1] = vmmc_module_get_pin(b);
link->modules[0] = a;
link->modules[1] = b;
return 0;
}
void vmmc_link_put(struct vmmc_link *link)
{
vmmc_link_disable(link);
vmmc_module_sync(link->modules[0]);
vmmc_module_sync(link->modules[1]);
vmmc_module_put_pin(link->modules[0], link->pins[0]);
vmmc_module_put_pin(link->modules[1], link->pins[1]);
}
void vmmc_link_enable(struct vmmc_link *link)
{
vmmc_module_set_pin_input(link->modules[0], link->pins[0],
link->modules[1]);
vmmc_module_set_pin_input(link->modules[1], link->pins[1],
link->modules[0]);
vmmc_module_enable(link->modules[0]);
vmmc_module_enable(link->modules[1]);
}
void vmmc_link_disable(struct vmmc_link *link)
{
vmmc_module_set_pin_input(link->modules[0], link->pins[0], NULL);
vmmc_module_set_pin_input(link->modules[1], link->pins[1], NULL);
vmmc_module_disable(link->modules[0]);
vmmc_module_disable(link->modules[1]);
}

View file

@ -1,64 +0,0 @@
#ifndef __VMMC_MODULE_H__
#define __VMMC_MODULE_H__
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/tapi/tapi.h>
struct vmmc_module;
struct vmmc_module_ops {
int (*sync)(struct vmmc_module *);
int (*enable)(struct vmmc_module *, bool enable);
};
struct vmmc_module
{
unsigned int id;
size_t num_pins;
unsigned int *pins;
const struct vmmc_module_ops *ops;
unsigned long flags;
#define VMMC_MODULE_FLAG_PIN_USED(x) (x)
#define VMMC_MODULE_FLAG_MODIFIED 31
struct mutex lock;
struct list_head head;
unsigned int refcount;
};
int vmmc_module_init(struct vmmc_module *module, size_t num_pins,
const struct vmmc_module_ops *ops);
int vmmc_module_sync(struct vmmc_module *module);
struct vmmc_link {
struct vmmc_module *modules[2];
unsigned int pins[2];
};
struct vmmc_endpoint {
struct tapi_endpoint ep;
struct vmmc_module *module;
};
void vmmc_link_enable(struct vmmc_link *link);
void vmmc_link_disable(struct vmmc_link *link);
unsigned int vmmc_link_init(struct vmmc_link *link,
struct vmmc_module *a, struct vmmc_module *b);
void vmmc_link_put(struct vmmc_link *link);
int vmmc_module_get_pin(struct vmmc_module *module);
void vmmc_module_put_pin(struct vmmc_module *module, unsigned int pin);
void vmmc_module_set_pin_input(struct vmmc_module *module, unsigned int pin,
struct vmmc_module *input);
static inline struct vmmc_module *tapi_endpoint_to_vmmc_module(struct tapi_endpoint *ep)
{
return tapi_endpoint_get_data(ep);
}
#endif

View file

@ -1,48 +0,0 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/tapi/tapi.h>
#include "vmmc.h"
#include "vmmc-port.h"
#include "vmmc-alm.h"
#include "vmmc-sig.h"
int vmmc_port_ring(struct tapi_device *tdev, struct tapi_port *port, bool ring)
{
struct vmmc *vmmc = tdev_to_vmmc(tdev);
return vmmc_alm_set_state(&vmmc->ports[port->id].alm,
ring ? VMMC_ALM_STATE_RING : VMMC_ALM_STATE_ONHOOK);
}
int vmmc_port_send_dtmf_event(struct tapi_device *tdev,
struct tapi_port *port, struct tapi_dtmf_event *event)
{
return 0;
}
struct vmmc_port *vmmc_port_init(struct vmmc *vmmc, struct vmmc_port *port,
struct tapi_port *tport, unsigned int id)
{
vmmc_alm_init(&port->alm, vmmc, id);
vmmc_sig_init(&port->sig, vmmc, id);
port->sig_pin = vmmc_module_get_pin(&port->sig.module);
vmmc_module_set_pin_input(&port->sig.module, port->sig_pin,
&port->alm.module);
vmmc_module_sync(&port->sig.module);
vmmc_alm_set_state(&port->alm, VMMC_ALM_STATE_ONHOOK);
tport->id = id;
tapi_endpoint_set_data(&tport->ep, &port->alm.module);
return port;
}
void vmmc_port_put(struct vmmc *vmmc, struct vmmc_port *port)
{
vmmc_module_put_pin(&port->sig.module, port->sig_pin);
}

View file

@ -1,22 +0,0 @@
#ifndef __VMMC_PORT_H__
#define __VMMC_PORT_H__
#include "vmmc-alm.h"
#include "vmmc-sig.h"
void vmmc_port_free(struct vmmc *vmmc, struct vmmc_port *port);
int vmmc_port_ring(struct tapi_device *tdev, struct tapi_port *port, bool ring);
int vmmc_port_send_dtmf_event(struct tapi_device *tdev,
struct tapi_port *port, struct tapi_dtmf_event *event);
struct vmmc_port *vmmc_port_init(struct vmmc *vmmc, struct vmmc_port *port,
struct tapi_port *tport, unsigned int id);
struct vmmc_port
{
struct vmmc_alm alm;
struct vmmc_sig sig;
unsigned int sig_pin;
};
#endif

View file

@ -1,19 +0,0 @@
#ifndef __VMMC_SIG_H__
#define __VMMC_SIG_H__
#include "vmmc-module.h"
struct vmmc_sig {
struct vmmc *vmmc;
unsigned int id;
struct vmmc_module module;
uint32_t sig_cache;
uint32_t dtmfr_cache;
};
int vmmc_sig_init(struct vmmc_sig *sig, struct vmmc *vmmc, unsigned int id);
void vmmc_sig_dtmf_event_handler(struct vmmc *vmmc, uint32_t event, uint32_t data);
#endif

View file

@ -1,69 +0,0 @@
#include <linux/kernel.h>
#include "vmmc.h"
#include "vmmc-sig.h"
#include "vmmc-cmds.h"
static struct vmmc_sig *vmmc_module_to_sig(struct vmmc_module *module)
{
return container_of(module, struct vmmc_sig, module);
}
static int vmmc_sig_enable(struct vmmc_module *module, bool enabled)
{
struct vmmc_sig *sig = vmmc_module_to_sig(module);
return 0;
sig->sig_cache = VMMC_CMD_SIG_SET_ENABLE(sig->sig_cache, enabled);
return vmmc_command_write(sig->vmmc, VMMC_CMD_SIG(sig->id), &sig->sig_cache);
}
static int vmmc_sig_sync(struct vmmc_module *module)
{
struct vmmc_sig *sig = vmmc_module_to_sig(module);
sig->sig_cache = VMMC_CMD_SIG_SET_INPUTS(sig->sig_cache,
module->pins[0], module->pins[1]);
vmmc_command_write(sig->vmmc, VMMC_CMD_SIG(sig->id),
&sig->sig_cache);
return vmmc_command_write(sig->vmmc, VMMC_CMD_DTMFR(sig->id),
&sig->dtmfr_cache);
}
static const struct vmmc_module_ops vmmc_sig_ops = {
.enable = vmmc_sig_enable,
.sync = vmmc_sig_sync,
};
int vmmc_sig_init(struct vmmc_sig *sig, struct vmmc *vmmc, unsigned int id)
{
int ret;
ret = vmmc_module_init(&sig->module, 2, &vmmc_sig_ops);
if (ret)
return ret;
sig->id = id;
sig->module.id = id + 0x1e;
sig->vmmc = vmmc;
sig->sig_cache = VMMC_CMD_SIG_DATA(1, 1, 0, 0, 0, 0, 0);
sig->dtmfr_cache = VMMC_CMD_DTMFR_DATA(1, 1, id);
vmmc_register_module(vmmc, &sig->module);
vmmc_command_write(sig->vmmc, VMMC_CMD_SIG(sig->id),
&sig->sig_cache);
vmmc_command_write(sig->vmmc, VMMC_CMD_DTMFR(sig->id),
&sig->dtmfr_cache);
return ret;
}
void vmmc_sig_dtmf_event_handler(struct vmmc *vmmc, uint32_t id, uint32_t data)
{
tapi_report_dtmf_event(&vmmc->tdev, &vmmc->tdev.ports[id], data & 0xf);
}

View file

@ -1,73 +0,0 @@
#include <linux/kernel.h>
#include <linux/tapi/tapi.h>
#include <linux/skbuff.h>
#include "vmmc.h"
#include "vmmc-coder.h"
struct vmmc_tapi_stream {
struct vmmc_coder *coder;
struct tapi_stream stream;
};
struct vmmc_tapi_stream *tapi_to_vmmc_stream(struct tapi_stream * stream)
{
return container_of(stream, struct vmmc_tapi_stream, stream);
}
struct tapi_stream *vmmc_stream_alloc(struct tapi_device *tdev)
{
struct vmmc *vmmc = tdev_to_vmmc(tdev);
struct vmmc_tapi_stream *stream;
struct vmmc_coder *coder;
coder = vmmc_coder_get(vmmc);
if (!coder)
return ERR_PTR(-ENODEV);
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (!stream)
return ERR_PTR(-ENOMEM);
stream->coder = coder;
coder->stream = &stream->stream;
tapi_endpoint_set_data(&stream->stream.ep, &coder->module);
return &stream->stream;
}
void vmmc_stream_free(struct tapi_device *tdev, struct tapi_stream *tstream)
{
struct vmmc *vmmc = tdev_to_vmmc(tdev);
struct vmmc_tapi_stream *stream = tapi_to_vmmc_stream(tstream);
stream->coder->stream = NULL;
vmmc_coder_put(vmmc, stream->coder);
kfree(stream);
}
int vmmc_stream_start(struct tapi_device *tdev, struct tapi_stream *stream)
{
return 0;
}
int vmmc_stream_stop(struct tapi_device *tdev, struct tapi_stream *stream)
{
return 0;
}
int vmmc_stream_send(struct tapi_device *tdev, struct tapi_stream *stream,
struct sk_buff *skb)
{
struct vmmc *vmmc = tdev_to_vmmc(tdev);
struct vmmc_coder *coder = tapi_to_vmmc_stream(stream)->coder;
vmmc_send_paket(vmmc, coder->id, skb);
return 0;
}
/*
int vmmc_stream_recv(struct vmmc_stream *stream)
{
tapi_stream_recv(&stream->coder->vmmc->tdev stream->stream, skb);
}*/

View file

@ -1,10 +0,0 @@
#ifndef __VMMC_STREAM_H__
#define __VMMC_STREAM_H__
struct tapi_stream *vmmc_stream_alloc(struct tapi_device *tdev);
void vmmc_stream_free(struct tapi_device *tdev, struct tapi_stream *stream);
int vmmc_stream_start(struct tapi_device *tdev, struct tapi_stream *stream);
int vmmc_stream_send(struct tapi_device *tdev, struct tapi_stream *stream,
struct sk_buff *skb);
#endif

View file

@ -1,90 +0,0 @@
static uint32_t magic_init[] = {
/* ALI INIT */
/*0x0601210c, 0x88002000, 0x20000000, 0x00000000, 0xffffffff,*/
/* COD_CHAN_SPEECH_ECMD */
/*0x06016110, 0x2462f700, 0x20002000, 0x00000000, 0x00000000, 0xffffffff,*/
/* COD_DEC_STAT_ECMD */
/*0x06017504, 0x00c00000, 0xffffffff,*/
/* COD_JB_CONF_ECMD */
/*0x06017208, 0x16410050, 0x005005a0, 0xffffffff,*/
/* SIG_RTP_SUP */
/*0x0601500c, 0x00000000, 0x00000060, 0x0712007f, 0xffffffff,*/
/* SIG_CHAN */
/*0x06014104, 0xc0190000, 0xffffffff,*/
/* SIG_CIDS_CTRL_ECMD */
/*0x06014204, 0x3811e000, 0xffffffff, */
/* SIG_DTMFATG_DATA */
/*0x06014b04, 0x00010000, 0xffffffff,*/
/* SIG_DTMFATG_CTRL */
/*0x06014304, 0x6a110000, 0xffffffff,
0x0601cc04, 0xe21c2000, 0xffffffff,
0x06014404, 0xb0110000, 0xffffffff,
0x06014a04, 0x04510000, 0xffffffff,
0x06014604, 0x04560000, 0xffffffff,
0x06014104, 0xc0190000, 0xffffffff,*/
/* COD_CHAN_RTP_SUP_CFG_USD */
/*0x06017124, 0x00000000, 0x00008880, 0xe3e4e5e6, 0x72727272, 0x72727272,
0x0f7f1261, 0x7374097f, 0xf1f06767, 0x04047675, 0xffffffff,*/
/* COD_CHAN_RTP_SUP_CFG_DS */
/* 0x06017920, 0x08006364, 0x65667272, 0x72727272, 0x72720f7f, 0x12617374,
0x097f7170, 0x67670404, 0x76750000, 0xffffffff, */
/* OPMODE_CMD */
0x01010004, 0x00010000, 0xffffffff,
0x01000004, 0x00030000, 0xffffffff,
/*0x01010004, 0x00010000, 0xffffffff,*/
/* COD_CHAN_RTP_SUP_CFG_US */
/* 0x06017124, 0x00000000, 0x00008880, 0xe3e4e5e6, 0x72727272, 0x72727272,
0x0f7f1261, 0x7374097f, 0xf1f06767, 0x04047675, 0xffffffff, */
/* COD_CHAN_RTP_SUP_CFG_DS */
/* 0x06017920, 0x08006364, 0x65667272, 0x72727272, 0x72720f7f, 0x12617374,
0x097f7170, 0x67670404, 0x76750000, 0xffffffff, */
/* COD_JB_CONF */
/* 0x06017208, 0x16410050, 0x005005a0, 0xffffffff, */
/* COD_CHAN_RTP_SUP_CFG_US */
/*0x06017108, 0x00000000, 0x00008880, 0xffffffff,*/
/* COD_CHAN_RTP_TIMESTAMP */
/*0x06017004, 0x00000000, 0xffffffff,*/
/* SIG_RTP_SUP */
/* 0x0601500c, 0x00000000, 0x00000062, 0x0712007f, 0xffffffff,*/
/* SIG_DTMFR_CTRL */
/*0x06014404, 0xb0010000, 0xffffffff,*/
/* COD_CHAN_SPEECH */
/* 0x06016110, 0x0462d600, 0x20002000, 0x00000000, 0x00000000, 0xffffffff, */
/* ALI_CHAN */
0x0601210c, 0x88232000, 0x20000000, 0x00000000, 0xffffffff,
/* SIG_CHAN */
/*0x06014104, 0xc5190000, 0xffffffff,*/
/* SIG_DTMFR_CTRL_ECMD */
/*0x06014404, 0x30010000, 0xffffffff,*/
/* SIG_CHAN_ECMD */
/*0x06014104, 0x45190000, 0xffffffff,*/
};
static void setup_alm(struct mps *mps, int chan)
{
uint32_t *data = magic_init;
int size, i;
/* data[0] = ALI_CHAN_DATA1(1, 0, 0, 1, 1, 0, 0);
data[1] = ALI_CHAN_DATA2(0, 0, 0);
data[2] = ALI_CHAN_DATA3(0, 0);*/
size = 1;
for (i = 1; i < ARRAY_SIZE(magic_init); ++i) {
if (magic_init[i] == 0xffffffff) {
printk("cmd: %x\n", *data);
VMMC_FIFO_fifo_in(&mps->mbox_cmd.downstream, data, size);
size = 0;
data = &magic_init[i+1];
mdelay(500);
} else {
size += 1;
}
}
/* VMMC_FIFO_mailbox_command_write(&mps->mbox_cmd, MPS_CMD_ALI(chan), data);*/
}

View file

@ -1,68 +0,0 @@
#ifndef __VMMC_H__
#include <linux/list.h>
#include <linux/tapi/tapi.h>
#include "mps.h"
#include "vmmc-module.h"
struct vmmc
{
struct mps *mps;
struct device *dev;
struct vmmc_port *ports;
struct completion firmware_loaded_completion;
struct completion cmd_completion;
struct mps_mailbox mbox_cmd;
struct mps_mailbox mbox_data;
struct mps_fifo fifo_event;
int irq_fw_loaded;
int irq_mbox_cmd;
int irq_mbox_data;
int irq_event_fifo;
int irq_cmd_error;
unsigned int num_coders;
struct vmmc_coder *coder;
unsigned long coder_used;
struct list_head modules;
struct tapi_device tdev;
struct sk_buff_head recv_queue;
struct sk_buff_head send_queue;
};
static inline struct vmmc *tdev_to_vmmc(struct tapi_device *tdev)
{
return container_of(tdev, struct vmmc, tdev);
}
static inline void vmmc_register_module(struct vmmc *vmmc,
struct vmmc_module *module)
{
list_add_tail(&module->head, &vmmc->modules);
}
static inline void vmmc_unregister_module(struct vmmc *vmmc,
struct vmmc_module *module)
{
list_del(&module->head);
}
int vmmc_command_write(struct vmmc *vmmc, uint32_t cmd,
const uint32_t *data);
int vmmc_command_read(struct vmmc *vmmc, uint32_t cmd, uint32_t *result);
struct vmmc_coder *vmmc_coder_get(struct vmmc *);
void vmmc_coder_put(struct vmmc *, struct vmmc_coder *);
void vmmc_init_coders(struct vmmc *);
void vmmc_send_paket(struct vmmc *vmmc, unsigned int chan, struct sk_buff *skb);
#endif

View file

@ -1,7 +0,0 @@
tapi-objs := tapi-core.o tapi-port.o tapi-input.o
tapi-objs += tapi-control.o
tapi-objs += tapi-stream.o
tapi-objs += tapi-sysfs-port.o
obj-m += tapi.o

View file

@ -1,193 +0,0 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tapi/tapi.h>
#include <linux/tapi/tapi-ioctl.h>
/* FIXME Does it acutally make sense to allow more then one application at a
* time to open the control device? For example calling sync from one app will
* also sync all others. */
struct tapi_control_file {
struct tapi_device *tdev;
struct list_head links;
};
static struct tapi_endpoint *tapi_lookup_endpoint(struct tapi_device *tdev,
unsigned int ep_id)
{
struct tapi_stream *stream;
if (ep_id < tdev->num_ports)
return &tdev->ports[ep_id].ep;
list_for_each_entry(stream, &tdev->streams, head) {
if (stream->ep.id == ep_id)
return &stream->ep;
}
return ERR_PTR(-ENOENT);
}
static inline struct tapi_device *inode_to_tdev(struct inode *inode)
{
return container_of(inode->i_cdev, struct tapi_char_device, cdev)->tdev;
}
static int tapi_control_open(struct inode *inode, struct file *file)
{
int ret;
struct tapi_device *tdev = inode_to_tdev(inode);
struct tapi_control_file *tctrl;
get_device(&tdev->dev);
tctrl = kzalloc(sizeof(*tctrl), GFP_KERNEL);
if (!tctrl) {
ret = -ENOMEM;
goto err_put_device;
}
INIT_LIST_HEAD(&tctrl->links);
tctrl->tdev = tdev;
file->private_data = tctrl;
return 0;
err_put_device:
put_device(&tdev->dev);
return ret;
}
static int tapi_control_release(struct inode *inode, struct file *file)
{
struct tapi_control_file *tctrl = file->private_data;
struct tapi_link *link;
if (tctrl) {
list_for_each_entry(link, &tctrl->links, head)
tapi_link_free(tctrl->tdev, link);
put_device(&tctrl->tdev->dev);
}
return 0;
}
static long tapi_control_ioctl_link_alloc(struct tapi_control_file *tctrl,
unsigned long arg)
{
struct tapi_link *link;
struct tapi_endpoint *ep1, *ep2;
ep1 = tapi_lookup_endpoint(tctrl->tdev, arg >> 16);
ep2 = tapi_lookup_endpoint(tctrl->tdev, arg & 0xffff);
link = tapi_link_alloc(tctrl->tdev, ep1, ep2);
if (IS_ERR(link))
return PTR_ERR(link);
list_add_tail(&link->head, &tctrl->links);
return link->id;
}
struct tapi_link *tapi_control_lookup_link(struct tapi_control_file *tctrl,
unsigned int id)
{
struct tapi_link *link;
list_for_each_entry(link, &tctrl->links, head) {
if (link->id == id)
return link;
}
return NULL;
}
static long tapi_control_ioctl_link_free(struct tapi_control_file *tctrl,
unsigned long arg)
{
struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
if (!link)
return -ENOENT;
tapi_link_free(tctrl->tdev, link);
list_del(&link->head);
return 0;
}
static long tapi_control_ioctl_link_enable(struct tapi_control_file *tctrl,
unsigned long arg)
{
struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
if (!link)
return -ENOENT;
return tapi_link_enable(tctrl->tdev, link);
}
static long tapi_control_ioctl_link_disable(struct tapi_control_file *tctrl,
unsigned long arg)
{
struct tapi_link *link = tapi_control_lookup_link(tctrl, arg);
if (!link)
return -ENOENT;
return tapi_link_disable(tctrl->tdev, link);
}
static long tapi_control_ioctl_sync(struct tapi_control_file *tctrl)
{
return tapi_sync(tctrl->tdev);
}
static long tapi_control_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
struct tapi_control_file *tctrl = file->private_data;
switch (cmd) {
case TAPI_CONTROL_IOCTL_LINK_ALLOC:
ret = tapi_control_ioctl_link_alloc(tctrl, arg);
break;
case TAPI_CONTROL_IOCTL_LINK_FREE:
ret = tapi_control_ioctl_link_free(tctrl, arg);
break;
case TAPI_CONTROL_IOCTL_LINK_ENABLE:
ret = tapi_control_ioctl_link_enable(tctrl, arg);
break;
case TAPI_CONTROL_IOCTL_LINK_DISABLE:
ret = tapi_control_ioctl_link_disable(tctrl, arg);
break;
case TAPI_CONTROL_IOCTL_SYNC:
ret = tapi_control_ioctl_sync(tctrl);
break;
default:
return -EINVAL;
}
return ret;
}
static const struct file_operations tapi_control_file_ops = {
.owner = THIS_MODULE,
.open = tapi_control_open,
.release = tapi_control_release,
.unlocked_ioctl = tapi_control_ioctl,
};
int tapi_register_control_device(struct tapi_device* tdev)
{
dev_set_name(&tdev->control_dev.dev, "tapi%uC", tdev->id);
return tapi_char_device_register(tdev, &tdev->control_dev, &tapi_control_file_ops);
}

View file

@ -1,250 +0,0 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/cdev.h>
#include <linux/err.h>
#include <linux/tapi/tapi.h>
void tapi_alloc_input(struct tapi_device *tdev, struct tapi_port *port);
int tapi_register_port_device(struct tapi_device* tdev, struct tapi_port *port);
int tapi_register_stream_device(struct tapi_device* tdev);
int tapi_register_control_device(struct tapi_device* tdev);
static struct class *tapi_class;
static int tapi_major;
#define TAPI_MAX_MINORS 255
static bool tapi_minors[TAPI_MAX_MINORS];
static int tapi_get_free_minor(void)
{
int i;
for (i = 0; i < TAPI_MAX_MINORS; ++i) {
if (!tapi_minors[i]) {
tapi_minors[i] = true;
return i;
}
}
return -1;
}
/*
int tapi_port_send_dtmf_events(struct tapi_device *tdev, unsigned int port, struct tapi_dtmf *, size_t num_events, unsigned int dealy)
{
}
EXPORT_SYMBOL_GPL(tapi_port_send_dtmf_events);
*/
void tapi_report_hook_event(struct tapi_device *tdev, struct tapi_port *port,
bool on)
{
struct tapi_event event;
event.type = TAPI_EVENT_TYPE_HOOK;
event.port = port->id;
event.hook.on = on;
tapi_report_event(tdev, &event);
}
EXPORT_SYMBOL_GPL(tapi_report_hook_event);
void tapi_report_dtmf_event(struct tapi_device *tdev, struct tapi_port *port,
unsigned char code)
{
struct tapi_event event;
event.type = TAPI_EVENT_TYPE_DTMF;
event.port = port->id;
event.dtmf.code = code;
tapi_report_event(tdev, &event);
}
EXPORT_SYMBOL_GPL(tapi_report_dtmf_event);
struct tapi_stream *tapi_stream_alloc(struct tapi_device *tdev)
{
struct tapi_stream *stream;
printk("tdev %p\n", tdev);
if (!tdev->ops || !tdev->ops->stream_alloc)
return ERR_PTR(-ENOSYS);
stream = tdev->ops->stream_alloc(tdev);
printk("stream %p\n", stream);
if (IS_ERR(stream))
return stream;
stream->id = atomic_inc_return(&tdev->stream_id) - 1;
stream->ep.id = stream->id;
/* mutex_lock(&tdev->lock);*/
list_add_tail(&stream->head, &tdev->streams);
/* mutex_unlock(&tdev->lock);*/
return stream;
}
EXPORT_SYMBOL_GPL(tapi_stream_alloc);
void tapi_stream_free(struct tapi_device *tdev, struct tapi_stream *stream)
{
mutex_lock(&tdev->lock);
list_del(&stream->head);
mutex_unlock(&tdev->lock);
tdev->ops->stream_free(tdev, stream);
}
EXPORT_SYMBOL_GPL(tapi_stream_free);
struct tapi_link *tapi_link_alloc(struct tapi_device *tdev,
struct tapi_endpoint *ep1, struct tapi_endpoint *ep2)
{
struct tapi_link *link;
if (!tdev->ops || !tdev->ops->link_alloc)
return ERR_PTR(-ENOSYS);
link = tdev->ops->link_alloc(tdev, ep1, ep2);
if (IS_ERR(link))
return link;
link->id = atomic_inc_return(&tdev->link_id) - 1;
/*
mutex_lock(&tdev->lock);
list_add_tail(&link->head, &tdev->links);
mutex_unlock(&tdev->lock);
*/
return link;
}
EXPORT_SYMBOL_GPL(tapi_link_alloc);
void tapi_link_free(struct tapi_device *tdev, struct tapi_link *link)
{
/*
mutex_lock(&tdev->lock);
list_del(&link->head);
mutex_unlock(&tdev->lock);
*/
tdev->ops->link_free(tdev, link);
}
EXPORT_SYMBOL_GPL(tapi_link_free);
int tapi_char_device_register(struct tapi_device *tdev,
struct tapi_char_device *tchrdev, const struct file_operations *fops)
{
int ret;
struct device *dev = &tchrdev->dev;
dev_t devt;
int minor = tapi_get_free_minor();
devt = MKDEV(tapi_major, minor);
dev->devt = devt;
dev->class = tapi_class;
dev->parent = &tdev->dev;
tchrdev->tdev = tdev;
cdev_init(&tchrdev->cdev, fops);
tchrdev->cdev.owner = THIS_MODULE;
ret = cdev_add(&tchrdev->cdev, devt, 1);
if (ret)
return ret;
ret = device_register(&tchrdev->dev);
if (ret)
goto err_cdev_del;
return 0;
err_cdev_del:
cdev_del(&tchrdev->cdev);
return ret;
}
int tapi_device_register(struct tapi_device *tdev, const char *name,
struct device *parent)
{
static atomic_t tapi_device_id = ATOMIC_INIT(0);
int ret, i;
tdev->dev.class = tapi_class;
tdev->dev.parent = parent;
dev_set_name(&tdev->dev, "%s", name);
ret = device_register(&tdev->dev);
if (ret)
return ret;
tdev->id = atomic_inc_return(&tapi_device_id) - 1;
mutex_init(&tdev->lock);
INIT_LIST_HEAD(&tdev->streams);
INIT_LIST_HEAD(&tdev->links);
atomic_set(&tdev->link_id, 0);
atomic_set(&tdev->stream_id, tdev->num_ports);
tapi_register_stream_device(tdev);
tapi_register_control_device(tdev);
for (i = 0; i < tdev->num_ports; ++i) {
tapi_port_alloc(tdev, i);
tapi_alloc_input(tdev, &tdev->ports[i]);
tapi_register_port_device(tdev, &tdev->ports[i]);
tdev->ports[i].id = i;
tdev->ports[i].ep.id = i;
}
return 0;
}
EXPORT_SYMBOL_GPL(tapi_device_register);
void tapi_device_unregister(struct tapi_device *tdev)
{
device_unregister(&tdev->dev);
}
EXPORT_SYMBOL_GPL(tapi_device_unregister);
static int __init tapi_class_init(void)
{
int ret;
dev_t dev;
tapi_class = class_create(THIS_MODULE, "tapi");
if (IS_ERR(tapi_class)) {
ret = PTR_ERR(tapi_class);
printk(KERN_ERR "tapi: Failed to create device class: %d\n", ret);
goto err;
}
ret = alloc_chrdev_region(&dev, 0, TAPI_MAX_MINORS, "tapi");
if (ret) {
printk(KERN_ERR "tapi: Failed to allocate chrdev region: %d\n", ret);
goto err_class_destory;
}
tapi_major = MAJOR(dev);
return 0;
err_class_destory:
class_destroy(tapi_class);
err:
return ret;
}
subsys_initcall(tapi_class_init);
static void __exit tapi_class_exit(void)
{
unregister_chrdev_region(MKDEV(tapi_major, 0), TAPI_MAX_MINORS);
class_destroy(tapi_class);
}
module_exit(tapi_class_exit);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("TAPI class");
MODULE_LICENSE("GPL");

View file

@ -1,99 +0,0 @@
#include <linux/tapi/tapi.h>
#include <linux/input.h>
static unsigned short tapi_keycodes[] = {
[0] = KEY_NUMERIC_0,
[1] = KEY_NUMERIC_1,
[2] = KEY_NUMERIC_2,
[3] = KEY_NUMERIC_3,
[4] = KEY_NUMERIC_4,
[5] = KEY_NUMERIC_5,
[6] = KEY_NUMERIC_6,
[7] = KEY_NUMERIC_7,
[8] = KEY_NUMERIC_8,
[9] = KEY_NUMERIC_9,
[10] = KEY_NUMERIC_STAR,
[11] = KEY_NUMERIC_POUND,
[12] = KEY_ENTER,
[13] = KEY_ESC,
};
static int tapi_input_event(struct input_dev *input, unsigned int type,
unsigned int code, int value)
{
struct tapi_device *tdev = dev_to_tapi(input->dev.parent);
struct tapi_port *port = input_get_drvdata(input);
if (type != EV_SND || code != SND_BELL)
return -EINVAL;
tapi_port_set_ring(tdev, port, value);
return 0;
}
void tapi_alloc_input(struct tapi_device *tdev, struct tapi_port *port)
{
struct input_dev *input;
int i;
char *phys;
input = input_allocate_device();
phys = kzalloc(sizeof("tapi/input000"), GFP_KERNEL);
sprintf(phys, "tapi/input%d", port->id);
input->name = "tapi";
input->phys = phys;
input->id.bustype = BUS_HOST;
input->dev.parent = &tdev->dev;
input->evbit[0] = BIT(EV_KEY) | BIT(EV_SND);
input->sndbit[0] = BIT(SND_BELL);
input->event = tapi_input_event;
input->keycodesize = sizeof(unsigned short);
input->keycodemax = ARRAY_SIZE(tapi_keycodes);
input->keycode = tapi_keycodes;
port->input = input;
for (i = 0; i < ARRAY_SIZE(tapi_keycodes); ++i)
__set_bit(tapi_keycodes[i], input->keybit);
input_set_drvdata(input, port);
input_register_device(input);
}
void tapi_report_event(struct tapi_device *tdev,
struct tapi_event *event)
{
unsigned short key_code;
struct input_dev *input;
if (!tdev || !tdev->ports)
return;
switch (event->type) {
case TAPI_EVENT_TYPE_HOOK:
if (event->hook.on)
key_code = KEY_ENTER;
else
key_code = KEY_ESC;
break;
case TAPI_EVENT_TYPE_DTMF:
key_code = tapi_keycodes[event->dtmf.code];
break;
default:
return;
}
input = tdev->ports[event->port].input;
input_report_key(input, key_code, 1);
input_sync(input);
input_report_key(input, key_code, 0);
input_sync(input);
}

View file

@ -1,62 +0,0 @@
static struct tapi_attr default_port[] = {
[PORTS] = {
.type = TAPI_TYPE_PORTS,
.name = "ports",
.description = "foobar",
.set = tapi_set_ports,
.get = tapi_get_ports,
},
};
static const struct nla_policy tapi_policy[] = {
[TAPI_ATTR_ID] = { .type = NLA_U32 },
[TAPI_ATTR_PORT] = { .type = NLA_U32 },
[TAPI_ATTR_ENDPOINT] = { .type = NLA_U32 },
[TAPI_ATTR_STREAM] = { .type = NLA_U32 }
};
static const struct nla_policy tapi_port_policy[] = {
[TAPI_PORT_ID] = { .type = NLA_U32 },
};
static const struct nla_policy tapi_endpoint_policy[] = {
[TAPI_ENDPOINT_ID] = { .type = NLA_U32 },
};
static const struct nla_policy tapi_stream_policy[] = {
[TAPI_STREAM_ID] = { .type = NLA_U32 },
};
static struct genl_family tapi_nl_family = {
.id = GENL_ID_GENERATE,
.name = "tapi",
.hdrsize = 0,
.version = 1,
.maxattr = ARRAY_SIZE(tapi_policy),
};
static struct genl_ops tapi_nl_ops[] = {
TAPI_NL_OP(TAPI_CMD_LIST, list_attr),
};
static int __init tapi_nl_init(void)
{
ret = genl_unregister_family(&tapi_nl_family);
if (ret)
return ret;
genl_register_ops(&tapi_nl_family, tapi_nl_ops);
return 0;
}
module_init(tapi_nl_init);
static void __exit tapi_nl_exit(void)
{
genl_unregister_family(&tapi_nl_family);
}

View file

@ -1,82 +0,0 @@
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tapi/tapi.h>
#include <linux/tapi/tapi-ioctl.h>
static inline struct tapi_port *tapi_char_device_to_port(struct tapi_char_device *chrdev)
{
return container_of(chrdev, struct tapi_port, chrdev);
}
static int tapi_port_open(struct inode *inode, struct file *file)
{
struct tapi_device *tdev = cdev_to_tapi_char_device(inode->i_cdev)->tdev;
get_device(&tdev->dev);
file->private_data = cdev_to_tapi_char_device(inode->i_cdev);
return 0;
}
static int tapi_port_release(struct inode *inode, struct file *file)
{
struct tapi_device *tdev = cdev_to_tapi_char_device(inode->i_cdev)->tdev;
put_device(&tdev->dev);
return 0;
}
static long tapi_port_ioctl_get_endpoint(struct tapi_device *tdev,
struct tapi_port *port, unsigned long arg)
{
return port->ep.id;
}
static long tapi_port_ioctl_set_ring(struct tapi_device *tdev,
struct tapi_port *port, unsigned long arg)
{
tapi_port_set_ring(tdev, port, arg);
return 0;
}
static long tapi_port_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
struct tapi_char_device *tchrdev = file->private_data;
struct tapi_device *tdev = tchrdev->tdev;
struct tapi_port *port = tapi_char_device_to_port(tchrdev);
switch (cmd) {
case TAPI_PORT_IOCTL_GET_ENDPOINT:
ret = tapi_port_ioctl_get_endpoint(tdev, port, arg);
break;
case TAPI_PORT_IOCTL_SET_RING:
ret = tapi_port_ioctl_set_ring(tdev, port, arg);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct file_operations tapi_port_file_ops = {
.owner = THIS_MODULE,
.open = tapi_port_open,
.release = tapi_port_release,
.unlocked_ioctl = tapi_port_ioctl,
};
int tapi_register_port_device(struct tapi_device* tdev, struct tapi_port *port)
{
dev_set_name(&port->chrdev.dev, "tapi%uP%u", tdev->id, port->id);
return tapi_char_device_register(tdev, &port->chrdev, &tapi_port_file_ops);
}

View file

@ -1,201 +0,0 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/tapi/tapi.h>
#include <linux/tapi/tapi-ioctl.h>
struct tapi_stream_file {
struct tapi_device *tdev;
struct tapi_stream *stream;
};
static inline struct tapi_device *inode_to_tdev(struct inode *inode)
{
return container_of(inode->i_cdev, struct tapi_char_device, cdev)->tdev;
}
static int tapi_stream_open(struct inode *inode, struct file *file)
{
int ret;
struct tapi_device *tdev = inode_to_tdev(inode);
struct tapi_stream_file *stream;
get_device(&tdev->dev);
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
if (!stream) {
ret = -ENOMEM;
goto err_put;
}
stream->stream = tapi_stream_alloc(tdev);
if (IS_ERR(stream->stream)) {
ret = PTR_ERR(stream->stream);
goto err_free;
}
stream->tdev = tdev;
init_waitqueue_head(&stream->stream->recv_wait);
skb_queue_head_init(&stream->stream->recv_queue);
file->private_data = stream;
return 0;
err_free:
kfree(stream);
err_put:
put_device(&tdev->dev);
return ret;
}
static int tapi_stream_release(struct inode *inode, struct file *file)
{
struct tapi_stream_file *stream = file->private_data;
if (stream) {
tapi_stream_free(stream->tdev, stream->stream);
put_device(&stream->tdev->dev);
kfree(stream);
}
return 0;
}
static long tapi_stream_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = 0;
struct tapi_stream_file *stream = file->private_data;
struct tapi_device *tdev = stream->tdev;
switch (cmd) {
case TAPI_STREAM_IOCTL_GET_ENDPOINT:
ret = stream->stream->ep.id;
break;
case TAPI_STREAM_IOCTL_CONFIGURE:
break;
case TAPI_STREAM_IOCTL_START:
ret = tapi_stream_start(tdev, stream->stream);
break;
case TAPI_STREAM_IOCTL_STOP:
ret = tapi_stream_stop(tdev, stream->stream);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static unsigned int tapi_stream_poll(struct file *file, struct poll_table_struct *wait)
{
struct tapi_stream_file *stream = file->private_data;
int ret;
poll_wait(file, &stream->stream->recv_wait, wait);
ret = POLLOUT;
if (!skb_queue_empty(&stream->stream->recv_queue))
ret |= POLLIN;
return ret;
}
static ssize_t tapi_stream_read(struct file *file, char __user *buffer,
size_t count, loff_t *offset)
{
struct tapi_stream_file *stream = file->private_data;
struct sk_buff *skb;
skb = skb_dequeue(&stream->stream->recv_queue);
if (!skb) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
do {
interruptible_sleep_on(&stream->stream->recv_wait);
skb = skb_dequeue(&stream->stream->recv_queue);
} while (skb == NULL && !signal_pending(current));
if (skb == NULL)
return -ERESTARTNOHAND;
}
if (skb->len > count) {
skb_queue_head(&stream->stream->recv_queue, skb);
return -EMSGSIZE;
}
if (copy_to_user(buffer, skb->data, skb->len)) {
skb_queue_head(&stream->stream->recv_queue, skb);
return -EFAULT;
}
count = skb->len;
kfree_skb(skb);
return count;
}
static ssize_t tapi_stream_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct tapi_stream_file *stream = file->private_data;
struct tapi_device *tdev = stream->tdev;
struct sk_buff *skb;
if (count == 0)
return 0;
skb = alloc_skb(count, GFP_USER);
if (!skb)
return -ENOMEM;
if (copy_from_user(skb_put(skb, count), buffer, count)) {
kfree_skb(skb);
return -EFAULT;
}
tdev->ops->stream_send(tdev, stream->stream, skb);
return count;
}
static const struct file_operations tapi_stream_file_ops = {
.owner = THIS_MODULE,
.read = tapi_stream_read,
.write = tapi_stream_write,
.open = tapi_stream_open,
.release = tapi_stream_release,
.poll = tapi_stream_poll,
.unlocked_ioctl = tapi_stream_ioctl,
};
int tapi_register_stream_device(struct tapi_device* tdev)
{
dev_set_name(&tdev->stream_dev.dev, "tapi%uS", tdev->id);
return tapi_char_device_register(tdev, &tdev->stream_dev, &tapi_stream_file_ops);
}
int tapi_stream_recv(struct tapi_device *tdev, struct tapi_stream * stream,
struct sk_buff *skb)
{
skb_queue_tail(&stream->recv_queue, skb);
wake_up(&stream->recv_wait);
return 0;
}
EXPORT_SYMBOL_GPL(tapi_stream_recv);

View file

@ -1,107 +0,0 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/err.h>
#include <linux/tapi/tapi.h>
struct tapi_sysfs_port {
struct tapi_device *tdev;
unsigned int id;
struct kobject kobj;
};
struct tapi_sysfs_entry {
ssize_t (*show)(struct tapi_device *, unsigned int port, char *);
ssize_t (*store)(struct tapi_device *, unsigned int port, const char *, size_t);
struct attribute attr;
};
static ssize_t tapi_port_store(struct kobject *kobj, struct attribute *attr,
const char *s, size_t len)
{
struct tapi_sysfs_port *port = container_of(kobj, struct tapi_sysfs_port, kobj);
struct tapi_sysfs_entry *entry = container_of(attr, struct tapi_sysfs_entry,
attr);
if (!entry->store)
return -ENOSYS;
return entry->store(port->tdev, port->id, s, len);
}
static ssize_t tapi_port_show(struct kobject *kobj, struct attribute *attr,
char *s)
{
return -ENOSYS;
}
#define TAPI_PORT_ATTR(_name, _mode, _show, _store) \
struct tapi_sysfs_entry tapi_port_ ## _name ## _attr = \
__ATTR(_name, _mode, _show, _store)
static int tapi_port_store_ring(struct tapi_device *tdev, unsigned int port,
const char *s, size_t len)
{
int ret;
unsigned long val;
ret = strict_strtoul(s, 10, &val);
if (ret)
return ret;
ret = tapi_port_set_ring(tdev, &tdev->ports[port], val);
if (ret)
return ret;
return len;
}
static TAPI_PORT_ATTR(ring, 0644, NULL, tapi_port_store_ring);
static struct attribute *tapi_port_default_attrs[] = {
&tapi_port_ring_attr.attr,
NULL,
};
static void tapi_port_free(struct kobject *kobj)
{
struct tapi_sysfs_port *port = container_of(kobj, struct tapi_sysfs_port, kobj);
kfree(port);
}
static struct sysfs_ops tapi_port_sysfs_ops = {
.show = tapi_port_show,
.store = tapi_port_store,
};
static struct kobj_type tapi_port_ktype = {
.release = tapi_port_free,
.sysfs_ops = &tapi_port_sysfs_ops,
.default_attrs = tapi_port_default_attrs,
};
struct tapi_sysfs_port *tapi_port_alloc(struct tapi_device *tdev, unsigned int id)
{
struct tapi_sysfs_port *port;
int ret;
port = kzalloc(sizeof(*port), GFP_KERNEL);
port->tdev = tdev;
port->id = id;
ret = kobject_init_and_add(&port->kobj, &tapi_port_ktype, &tdev->dev.kobj,
"port%d", id);
if (ret) {
kfree(port);
return ERR_PTR(ret);
}
return port;
}
void tapi_port_delete(struct tapi_sysfs_port *port)
{
kobject_del(&port->kobj);
kobject_put(&port->kobj);
}

View file

@ -155,12 +155,12 @@ define Build/InstallDev
$(CP) $(PKG_BUILD_DIR)/src/include/drv_dsl_cpe_cmv_danube.h $(1)/usr/include
endef
define Package/ltq-dsl-firmware-a/install
define Package/kmod-ltq-dsl-firmware-a/install
$(INSTALL_DIR) $(1)/lib/firmware/
$(CP) $(PKG_BUILD_DIR)/$(FW_BASE_NAME)_a_$(FW_A_FILE_VER).bin $(1)/lib/firmware/ModemHWE.bin
endef
define Package/ltq-dsl-firmware-b/install
define Package/kmod-ltq-dsl-firmware-b/install
$(INSTALL_DIR) $(1)/lib/firmware/
$(CP) $(PKG_BUILD_DIR)/$(FW_BASE_NAME)_b_$(FW_B_FILE_VER).bin $(1)/lib/firmware/ModemHWE.bin
endef

View file

@ -1,7 +1,5 @@
Index: drv_dsl_cpe_api-3.24.4.4/configure.in
===================================================================
--- drv_dsl_cpe_api-3.24.4.4.orig/configure.in 2009-08-13 13:39:21.000000000 +0200
+++ drv_dsl_cpe_api-3.24.4.4/configure.in 2010-10-14 02:14:55.000000000 +0200
--- a/configure.in
+++ b/configure.in
@@ -310,7 +310,7 @@
AC_ARG_ENABLE(kernelbuild,
AC_HELP_STRING(--enable-kernel-build=x,Set the target kernel build path),
@ -167,10 +165,8 @@ Index: drv_dsl_cpe_api-3.24.4.4/configure.in
])
AC_CONFIG_FILES([Makefile src/Makefile])
Index: drv_dsl_cpe_api-3.24.4.4/src/Makefile.am
===================================================================
--- drv_dsl_cpe_api-3.24.4.4.orig/src/Makefile.am 2009-07-03 14:06:34.000000000 +0200
+++ drv_dsl_cpe_api-3.24.4.4/src/Makefile.am 2010-10-14 02:14:55.000000000 +0200
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -303,7 +303,7 @@
drv_dsl_cpe_api_OBJS = "$(subst .c,.o,$(filter %.c,$(drv_dsl_cpe_api_SOURCES)))"
@ -195,10 +191,8 @@ Index: drv_dsl_cpe_api-3.24.4.4/src/Makefile.am
$(MAKE) ARCH=@KERNEL_ARCH@ -C @KERNEL_BUILD_PATH@ O=@KERNEL_BUILD_PATH@ M=$(PWD) modules
clean-generic:
Index: drv_dsl_cpe_api-3.24.4.4/src/include/drv_dsl_cpe_os_linux.h
===================================================================
--- drv_dsl_cpe_api-3.24.4.4.orig/src/include/drv_dsl_cpe_os_linux.h 2010-10-14 02:14:55.000000000 +0200
+++ drv_dsl_cpe_api-3.24.4.4/src/include/drv_dsl_cpe_os_linux.h 2010-10-14 02:14:55.000000000 +0200
--- a/src/include/drv_dsl_cpe_os_linux.h
+++ b/src/include/drv_dsl_cpe_os_linux.h
@@ -16,8 +16,6 @@
extern "C" {
#endif
@ -208,10 +202,25 @@ Index: drv_dsl_cpe_api-3.24.4.4/src/include/drv_dsl_cpe_os_linux.h
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -40,6 +38,7 @@
@@ -26,8 +24,10 @@
#include <linux/spinlock.h>
#include <linux/sched.h>
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
- #include <generated/utsrelease.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
+#include <linux/utsrelease.h>
+#else
+#include <generated/utsrelease.h>
#endif
#include <linux/types.h>
@@ -39,7 +39,8 @@
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
-#include <linux/smp_lock.h>
+//#include <linux/smp_lock.h>
+#include <asm/ioctl.h>
#ifdef INCLUDE_DSL_CPE_API_IFXOS_SUPPORT

View file

@ -59,8 +59,7 @@
/*
* Chip Specific Head File
*/
#include <lantiq.h>
#include <lantiq_regs.h>
#include <lantiq_soc.h>
#include "ifxmips_atm_core.h"
@ -2403,7 +2402,11 @@ static int __devinit ifx_atm_init(void)
/* create devices */
for ( port_num = 0; port_num < ATM_PORT_NUMBER; port_num++ ) {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
g_atm_priv_data.port[port_num].dev = atm_dev_register("ifxmips_atm", &g_ifx_atm_ops, -1, NULL);
#else
g_atm_priv_data.port[port_num].dev = atm_dev_register("ifxmips_atm", NULL, &g_ifx_atm_ops, -1, NULL);
#endif
if ( !g_atm_priv_data.port[port_num].dev ) {
err("failed to register atm device %d!", port_num);
ret = -EIO;

View file

@ -45,8 +45,7 @@
/*
* Chip Specific Head File
*/
#include <lantiq.h>
#include <lantiq_regs.h>
#include <lantiq_soc.h>
#include "ifxmips_compat.h"
#include "ifxmips_atm_core.h"
#include "ifxmips_atm_fw_danube.h"

View file

@ -93,7 +93,7 @@
/*
* Mailbox IGU1 Interrupt
*/
#define PPE_MAILBOX_IGU1_INT LQ_PPE_MBOX_INT
#define PPE_MAILBOX_IGU1_INT LTQ_PPE_MBOX_INT

View file

@ -26,7 +26,7 @@
#define IFX_PMU_MODULE_PPE_EMA (1 << 22)
#define IFX_PMU_MODULE_PPE_TOP (1 << 29)
#define ifx_pmu_set(a,b) {if(a == IFX_PMU_ENABLE) lq_pmu_enable(b); else lq_pmu_disable(b);}
#define ifx_pmu_set(a,b) {if(a == IFX_PMU_ENABLE) ltq_pmu_enable(b); else ltq_pmu_disable(b);}
#define PPE_TOP_PMU_SETUP(__x) ifx_pmu_set(IFX_PMU_MODULE_PPE_TOP, (__x))
#define PPE_SLL01_PMU_SETUP(__x) ifx_pmu_set(IFX_PMU_MODULE_PPE_SLL01, (__x))

View file

@ -29,7 +29,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
#include <linux/utsrelease.h>
#else
#include <generated/utsrelease.h>
#endif
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
@ -46,22 +50,21 @@
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include <lantiq.h>
#include <lantiq_regs.h>
#include <lantiq_soc.h>
#include "ifxmips_atm.h"
#define IFX_MEI_BSP
#include "ifxmips_mei_interface.h"
/*#define LQ_RCU_RST IFX_RCU_RST_REQ
#define LQ_RCU_RST_REQ_ARC_JTAG IFX_RCU_RST_REQ_ARC_JTAG
#define LQ_RCU_RST_REQ_DFE IFX_RCU_RST_REQ_DFE
#define LQ_RCU_RST_REQ_AFE IFX_RCU_RST_REQ_AFE
/*#define LTQ_RCU_RST IFX_RCU_RST_REQ
#define LTQ_RCU_RST_REQ_ARC_JTAG IFX_RCU_RST_REQ_ARC_JTAG
#define LTQ_RCU_RST_REQ_DFE IFX_RCU_RST_REQ_DFE
#define LTQ_RCU_RST_REQ_AFE IFX_RCU_RST_REQ_AFE
#define IFXMIPS_FUSE_BASE_ADDR IFX_FUSE_BASE_ADDR
#define IFXMIPS_ICU_IM0_IER IFX_ICU_IM0_IER
#define IFXMIPS_ICU_IM2_IER IFX_ICU_IM2_IER
#define LQ_MEI_INT IFX_MEI_INT
#define LQ_MEI_DYING_GASP_INT IFX_MEI_DYING_GASP_INT
#define LQ_MEI_BASE_ADDR IFX_MEI_SPACE_ACCESS
#define LTQ_MEI_INT IFX_MEI_INT
#define LTQ_MEI_DYING_GASP_INT IFX_MEI_DYING_GASP_INT
#define LTQ_MEI_BASE_ADDR IFX_MEI_SPACE_ACCESS
#define IFXMIPS_PMU_PWDCR IFX_PMU_PWDCR
#define IFXMIPS_MPS_CHIPID IFX_MPS_CHIPID
@ -73,40 +76,44 @@
#define ifxmips_port_free_pin ifx_gpio_pin_free
#define ifxmips_mask_and_ack_irq bsp_mask_and_ack_irq
#define IFXMIPS_MPS_CHIPID_VERSION_GET IFX_MCD_CHIPID_VERSION_GET
#define lq_r32(reg) __raw_readl(reg)
#define lq_w32(val, reg) __raw_writel(val, reg)
#define lq_w32_mask(clear, set, reg) lq_w32((lq_r32(reg) & ~clear) | set, reg)
#define ltq_r32(reg) __raw_readl(reg)
#define ltq_w32(val, reg) __raw_writel(val, reg)
#define ltq_w32_mask(clear, set, reg) ltq_w32((ltq_r32(reg) & ~clear) | set, reg)
*/
#define LQ_RCU_RST_REQ_DFE (1 << 7)
#define LQ_RCU_RST_REQ_AFE (1 << 11)
#define LQ_PMU_PWDCR ((u32 *)(LQ_PMU_BASE_ADDR + 0x001C))
#define LQ_PMU_PWDSR ((u32 *)(LQ_PMU_BASE_ADDR + 0x0020))
#define LQ_RCU_RST ((u32 *)(LQ_RCU_BASE_ADDR + 0x0010))
#define LQ_RCU_RST_ALL 0x40000000
#define LQ_ICU_BASE_ADDR (KSEG1 | 0x1F880200)
#define LTQ_RCU_RST_REQ_DFE (1 << 7)
#define LTQ_RCU_RST_REQ_AFE (1 << 11)
#define LQ_ICU_IM0_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0000))
#define LQ_ICU_IM0_IER ((u32 *)(LQ_ICU_BASE_ADDR + 0x0008))
#define LQ_ICU_IM0_IOSR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0010))
#define LQ_ICU_IM0_IRSR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0018))
#define LQ_ICU_IM0_IMR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0020))
#define LTQ_PMU_BASE (KSEG1 + LTQ_PMU_BASE_ADDR)
#define LTQ_RCU_BASE (KSEG1 + LTQ_RCU_BASE_ADDR)
#define LTQ_ICU_BASE (KSEG1 + LTQ_ICU_BASE_ADDR)
#define LTQ_PMU_PWDCR ((u32 *)(LTQ_PMU_BASE + 0x001C))
#define LTQ_PMU_PWDSR ((u32 *)(LTQ_PMU_BASE + 0x0020))
#define LTQ_RCU_RST ((u32 *)(LTQ_RCU_BASE + 0x0010))
#define LTQ_RCU_RST_ALL 0x40000000
#define LTQ_ICU_IM0_ISR ((u32 *)(LTQ_ICU_BASE + 0x0000))
#define LTQ_ICU_IM0_IER ((u32 *)(LTQ_ICU_BASE + 0x0008))
#define LTQ_ICU_IM0_IOSR ((u32 *)(LTQ_ICU_BASE + 0x0010))
#define LTQ_ICU_IM0_IRSR ((u32 *)(LTQ_ICU_BASE + 0x0018))
#define LTQ_ICU_IM0_IMR ((u32 *)(LTQ_ICU_BASE + 0x0020))
#define LQ_ICU_IM1_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0028))
#define LQ_ICU_IM2_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0050))
#define LQ_ICU_IM3_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0078))
#define LQ_ICU_IM4_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x00A0))
#define LTQ_ICU_IM1_ISR ((u32 *)(LTQ_ICU_BASE + 0x0028))
#define LTQ_ICU_IM2_ISR ((u32 *)(LTQ_ICU_BASE + 0x0050))
#define LTQ_ICU_IM3_ISR ((u32 *)(LTQ_ICU_BASE + 0x0078))
#define LTQ_ICU_IM4_ISR ((u32 *)(LTQ_ICU_BASE + 0x00A0))
#define LQ_ICU_OFFSET (LQ_ICU_IM1_ISR - LQ_ICU_IM0_ISR)
#define LQ_ICU_IM2_IER (LQ_ICU_IM0_IER + LQ_ICU_OFFSET)
#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
#define LTQ_ICU_IM2_IER (LTQ_ICU_IM0_IER + LTQ_ICU_OFFSET)
#define IFX_MEI_EMSG(fmt, args...) pr_err("[%s %d]: " fmt,__FUNCTION__, __LINE__, ## args)
#define IFX_MEI_DMSG(fmt, args...) pr_debug("[%s %d]: " fmt,__FUNCTION__, __LINE__, ## args)
#define LQ_FUSE_BASE (KSEG1 + 0x1F107354)
#define LTQ_FUSE_BASE (KSEG1 + 0x1F107354)
#ifdef CONFIG_LQ_MEI_FW_LOOPBACK
#ifdef CONFIG_LTQ_MEI_FW_LOOPBACK
//#define DFE_MEM_TEST
//#define DFE_PING_TEST
#define DFE_ATM_LOOPBACK
@ -193,9 +200,18 @@ static void *g_xdata_addr = NULL;
static u32 *mei_arc_swap_buff = NULL; // holding swap pages
extern void lq_mask_and_ack_irq(unsigned int irq_nr);
#define MEI_MASK_AND_ACK_IRQ lq_mask_and_ack_irq
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
extern void ltq_mask_and_ack_irq(unsigned int irq_nr);
#define MEI_MASK_AND_ACK_IRQ ltq_mask_and_ack_irq
#else
extern void ltq_mask_and_ack_irq(struct irq_data *d);
static void inline MEI_MASK_AND_ACK_IRQ(int x)
{
struct irq_data d;
d.irq = x;
ltq_mask_and_ack_irq(&d);
}
#endif
#define MEI_MAJOR 105
static int dev_major = MEI_MAJOR;
@ -704,9 +720,9 @@ IFX_MEI_FuseProg (DSL_DEV_Device_t * pDev)
u32 reg_data, fuse_value;
int i = 0;
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &reg_data);
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &reg_data);
while ((reg_data & 0x10000000) == 0) {
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &reg_data);
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &reg_data);
i++;
/* 0x4000 translate to about 16 ms@111M, so should be enough */
if (i == 0x4000)
@ -714,12 +730,12 @@ IFX_MEI_FuseProg (DSL_DEV_Device_t * pDev)
}
// STEP a: Prepare memory for external accesses
// Write fuse_en bit24
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &reg_data);
IFX_MEI_LongWordWrite ((u32) LQ_RCU_RST, reg_data | (1 << 24));
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &reg_data);
IFX_MEI_LongWordWrite ((u32) LTQ_RCU_RST, reg_data | (1 << 24));
IFX_MEI_FuseInit (pDev);
for (i = 0; i < 4; i++) {
IFX_MEI_LongWordRead ((u32) (LQ_FUSE_BASE) + i * 4, &fuse_value);
IFX_MEI_LongWordRead ((u32) (LTQ_FUSE_BASE) + i * 4, &fuse_value);
switch (fuse_value & 0xF0000) {
case 0x80000:
reg_data = ((fuse_value & RX_DILV_ADDR_BIT_MASK) |
@ -765,9 +781,9 @@ IFX_MEI_FuseProg (DSL_DEV_Device_t * pDev)
break;
}
}
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &reg_data);
IFX_MEI_LongWordWrite ((u32) LQ_RCU_RST, reg_data & ~(1 << 24));
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &reg_data);
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &reg_data);
IFX_MEI_LongWordWrite ((u32) LTQ_RCU_RST, reg_data & ~(1 << 24));
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &reg_data);
}
/**
@ -868,9 +884,9 @@ IFX_MEI_ResetARC (DSL_DEV_Device_t * pDev)
IFX_MEI_HaltArc (pDev);
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &arc_debug_data);
IFX_MEI_LongWordWrite ((u32) LQ_RCU_RST,
arc_debug_data | LQ_RCU_RST_REQ_DFE | LQ_RCU_RST_REQ_AFE);
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &arc_debug_data);
IFX_MEI_LongWordWrite ((u32) LTQ_RCU_RST,
arc_debug_data | LTQ_RCU_RST_REQ_DFE | LTQ_RCU_RST_REQ_AFE);
// reset ARC
IFX_MEI_LongWordWriteOffset (pDev, (u32) ME_RST_CTRL, MEI_SOFT_RESET);
@ -1034,8 +1050,8 @@ IFX_MEI_ArcJtagEnable (DSL_DEV_Device_t *dev, int enable)
ifxmips_port_clear_altsel1(0, 11);
ifxmips_port_set_open_drain(0, 11);
//enable ARC JTAG
IFX_MEI_LongWordRead ((u32) LQ_RCU_RST, &reg_data);
IFX_MEI_LongWordWrite ((u32) LQ_RCU_RST, reg_data | LQ_RCU_RST_REQ_ARC_JTAG);
IFX_MEI_LongWordRead ((u32) LTQ_RCU_RST, &reg_data);
IFX_MEI_LongWordWrite ((u32) LTQ_RCU_RST, reg_data | LTQ_RCU_RST_REQ_ARC_JTAG);
break;
case 0:
default:
@ -1045,8 +1061,6 @@ jtag_end:
if (meierr)
return DSL_DEV_MEI_ERR_FAILURE;
*/
printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
return DSL_DEV_MEI_ERR_SUCCESS;
};
@ -1333,17 +1347,17 @@ IFX_MEI_RunAdslModem (DSL_DEV_Device_t *pDev)
IFX_MEI_DownloadBootCode (pDev);
im0_register = (*LQ_ICU_IM0_IER) & (1 << 20);
im2_register = (*LQ_ICU_IM2_IER) & (1 << 20);
im0_register = (*LTQ_ICU_IM0_IER) & (1 << 20);
im2_register = (*LTQ_ICU_IM2_IER) & (1 << 20);
/* Turn off irq */
#ifdef CONFIG_LANTIQ_AMAZON_SE
#ifdef CONFIG_SOC_AMAZON_SE
disable_irq (IFXMIPS_USB_OC_INT0);
disable_irq (IFXMIPS_USB_OC_INT2);
#elif defined(CONFIG_LANTIQ_AR9)
disable_irq (IFXMIPS_USB_OC_INT0);
disable_irq (IFXMIPS_USB_OC_INT2);
#elif defined(CONFIG_SOC_LANTIQ_XWAY)
disable_irq (LQ_USB_OC_INT);
#elif defined(CONFIG_SOC_XWAY)
disable_irq (LTQ_USB_OC_INT);
#else
#error unkonwn arch
#endif
@ -1353,14 +1367,14 @@ IFX_MEI_RunAdslModem (DSL_DEV_Device_t *pDev)
MEI_WAIT_EVENT_TIMEOUT (DSL_DEV_PRIVATE(pDev)->wait_queue_modemready, 1000);
#ifdef CONFIG_LANTIQ_AMAZON_SE
#ifdef CONFIG_SOC_AMAZON_SE
MEI_MASK_AND_ACK_IRQ (IFXMIPS_USB_OC_INT0);
MEI_MASK_AND_ACK_IRQ (IFXMIPS_USB_OC_INT2);
#elif defined(CONFIG_LANTIQ_AMAZON_S)
MEI_MASK_AND_ACK_IRQ (IFXMIPS_USB_OC_INT0);
MEI_MASK_AND_ACK_IRQ (IFXMIPS_USB_OC_INT2);
#elif defined(CONFIG_SOC_LANTIQ_XWAY)
MEI_MASK_AND_ACK_IRQ (LQ_USB_OC_INT);
#elif defined(CONFIG_SOC_XWAY)
MEI_MASK_AND_ACK_IRQ (LTQ_USB_OC_INT);
#else
#error unkonwn arch
#endif
@ -1368,8 +1382,8 @@ IFX_MEI_RunAdslModem (DSL_DEV_Device_t *pDev)
/* Re-enable irq */
enable_irq(pDev->nIrq[IFX_DYING_GASP]);
*LQ_ICU_IM0_IER |= im0_register;
*LQ_ICU_IM2_IER |= im2_register;
*LTQ_ICU_IM0_IER |= im0_register;
*LTQ_ICU_IM2_IER |= im2_register;
if (DSL_DEV_PRIVATE(pDev)->modem_ready != 1) {
IFX_MEI_EMSG ("Modem failed to be ready!\n");
@ -1780,7 +1794,7 @@ static irqreturn_t IFX_MEI_IrqHandle (int int1, void *void0)
{
u32 scratch;
DSL_DEV_Device_t *pDev = (DSL_DEV_Device_t *) void0;
#if defined(CONFIG_LQ_MEI_FW_LOOPBACK) && defined(DFE_PING_TEST)
#if defined(CONFIG_LTQ_MEI_FW_LOOPBACK) && defined(DFE_PING_TEST)
dfe_loopback_irq_handler (pDev);
return IRQ_HANDLED;
#endif //CONFIG_AMAZON_S_MEI_FW_LOOPBACK
@ -1889,7 +1903,7 @@ DSL_BSP_GetEventCB (int (**ifx_adsl_callback)
}
#endif
#ifdef CONFIG_LQ_MEI_FW_LOOPBACK
#ifdef CONFIG_LTQ_MEI_FW_LOOPBACK
#define mte_reg_base (0x4800*4+0x20000)
/* Iridia Registers Address Constants */
@ -1949,20 +1963,20 @@ MEIWriteARCValue (u32 address, u32 value)
u32 i, check = 0;
/* Write address register */
IFX_MEI_WRITE_REGISTER_L (address, ME_DBG_WR_AD + LQ_MEI_BASE_ADDR);
IFX_MEI_WRITE_REGISTER_L (address, ME_DBG_WR_AD + LTQ_MEI_BASE_ADDR);
/* Write data register */
IFX_MEI_WRITE_REGISTER_L (value, ME_DBG_DATA + LQ_MEI_BASE_ADDR);
IFX_MEI_WRITE_REGISTER_L (value, ME_DBG_DATA + LTQ_MEI_BASE_ADDR);
/* wait until complete - timeout at 40 */
for (i = 0; i < 40; i++) {
check = IFX_MEI_READ_REGISTER_L (ME_ARC2ME_STAT + LQ_MEI_BASE_ADDR);
check = IFX_MEI_READ_REGISTER_L (ME_ARC2ME_STAT + LTQ_MEI_BASE_ADDR);
if ((check & ARC_TO_MEI_DBG_DONE))
break;
}
/* clear the flag */
IFX_MEI_WRITE_REGISTER_L (ARC_TO_MEI_DBG_DONE, ME_ARC2ME_STAT + LQ_MEI_BASE_ADDR);
IFX_MEI_WRITE_REGISTER_L (ARC_TO_MEI_DBG_DONE, ME_ARC2ME_STAT + LTQ_MEI_BASE_ADDR);
}
void
@ -2145,7 +2159,7 @@ DFE_Loopback_Test (void)
IFX_MEI_ControlModeSet (pDev, MEI_MASTER_MODE);
temp = 0;
_IFX_MEI_DBGLongWordWrite (pDev, MEI_DEBUG_DEC_AUX_MASK,
(u32) ME_XDATA_BASE_SH + LQ_MEI_BASE_ADDR, temp);
(u32) ME_XDATA_BASE_SH + LTQ_MEI_BASE_ADDR, temp);
IFX_MEI_ControlModeSet (pDev, JTAG_MASTER_MODE);
i = IFX_MEI_DFEMemoryAlloc (pDev, SDRAM_SEGMENT_SIZE * 16);
@ -2155,9 +2169,9 @@ DFE_Loopback_Test (void)
for (idx = 0; idx < i; idx++) {
DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].type = FREE_RELOAD;
IFX_MEI_WRITE_REGISTER_L ((((uint32_t) DSL_DEV_PRIVATE(pDev)->adsl_mem_info[idx].address) & 0x0fffffff),
LQ_MEI_BASE_ADDR + ME_XMEM_BAR_BASE + idx * 4);
LTQ_MEI_BASE_ADDR + ME_XMEM_BAR_BASE + idx * 4);
IFX_MEI_DMSG("bar%d(%X)=%X\n", idx,
LQ_MEI_BASE_ADDR + ME_XMEM_BAR_BASE +
LTQ_MEI_BASE_ADDR + ME_XMEM_BAR_BASE +
idx * 4, (((uint32_t)
((ifx_mei_device_private_t *)
pDev->pPriv)->adsl_mem_info[idx].
@ -2271,18 +2285,18 @@ IFX_MEI_InitDevice (int num)
sizeof (smmu_mem_info_t) * MAX_BAR_REGISTERS);
if (num == 0) {
pDev->nIrq[IFX_DFEIR] = LQ_MEI_INT;
pDev->nIrq[IFX_DYING_GASP] = LQ_MEI_DYING_GASP_INT;
pDev->base_address = LQ_MEI_BASE_ADDR;
pDev->nIrq[IFX_DFEIR] = LTQ_MEI_INT;
pDev->nIrq[IFX_DYING_GASP] = LTQ_MEI_DYING_GASP_INT;
pDev->base_address = KSEG1 + LTQ_MEI_BASE_ADDR;
/* Power up MEI */
#ifdef CONFIG_LANTIQ_AMAZON_SE
*LQ_PMU_PWDCR &= ~(1 << 9); // enable dsl
*LQ_PMU_PWDCR &= ~(1 << 15); // enable AHB base
*LTQ_PMU_PWDCR &= ~(1 << 9); // enable dsl
*LTQ_PMU_PWDCR &= ~(1 << 15); // enable AHB base
#else
temp = lq_r32(LQ_PMU_PWDCR);
temp = ltq_r32(LTQ_PMU_PWDCR);
temp &= 0xffff7dbe;
lq_w32(temp, LQ_PMU_PWDCR);
ltq_w32(temp, LTQ_PMU_PWDCR);
#endif
}
pDev->nInUse = 0;
@ -2443,7 +2457,7 @@ IFX_MEI_Ioctls (DSL_DEV_Device_t * pDev, int from_kernel, unsigned int command,
{
int i = 0;
int meierr = DSL_DEV_MEI_ERR_SUCCESS;
u32 base_address = LQ_MEI_BASE_ADDR;
u32 base_address = LTQ_MEI_BASE_ADDR;
DSL_DEV_WinHost_Message_t winhost_msg, m;
DSL_DEV_MeiDebug_t debugrdwr;
DSL_DEV_MeiReg_t regrdwr;
@ -2569,10 +2583,10 @@ IFX_MEI_Ioctls (DSL_DEV_Device_t * pDev, int from_kernel, unsigned int command,
IFX_MEI_IoctlCopyTo (from_kernel, (char *) lon, (char *) (&bsp_mei_version), sizeof (DSL_DEV_Version_t));
break;
#define LQ_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & ((1 << 4) - 1))
#define LTQ_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & ((1 << 4) - 1))
case DSL_FIO_BSP_GET_CHIP_INFO:
bsp_chip_info.major = 1;
bsp_chip_info.minor = LQ_MPS_CHIPID_VERSION_GET(*LQ_MPS_CHIPID);
bsp_chip_info.minor = LTQ_MPS_CHIPID_VERSION_GET(*LTQ_MPS_CHIPID);
IFX_MEI_IoctlCopyTo (from_kernel, (char *) lon, (char *) (&bsp_chip_info), sizeof (DSL_DEV_HwVersion_t));
meierr = DSL_DEV_MEI_ERR_SUCCESS;
break;
@ -2608,7 +2622,7 @@ IFX_MEI_Ioctls (DSL_DEV_Device_t * pDev, int from_kernel, unsigned int command,
void AMAZON_SE_MEI_ARC_MUX_Test(void)
{
u32 *p, i;
*LQ_RCU_RST |= LQ_RCU_RST_REQ_MUX_ARC;
*LTQ_RCU_RST |= LTQ_RCU_RST_REQ_MUX_ARC;
p = (u32*)(DFE_LDST_BASE_ADDR + IRAM0_BASE);
IFX_MEI_EMSG("Writing to IRAM0(%p)...\n", p);
@ -2657,7 +2671,7 @@ void AMAZON_SE_MEI_ARC_MUX_Test(void)
if (*p != 0xdeadbeef)
IFX_MEI_EMSG("%p: %#x\n", p, *p);
}
*LQ_RCU_RST &= ~LQ_RCU_RST_REQ_MUX_ARC;
*LTQ_RCU_RST &= ~LTQ_RCU_RST_REQ_MUX_ARC;
}
#endif
int
@ -2959,7 +2973,7 @@ IFX_MEI_ModuleInit (void)
for (i = 0; i <= DSL_BSP_CB_LAST ; i++)
dsl_bsp_event_callback[i].function = NULL;
#ifdef CONFIG_LQ_MEI_FW_LOOPBACK
#ifdef CONFIG_LTQ_MEI_FW_LOOPBACK
IFX_MEI_DMSG("Start loopback test...\n");
DFE_Loopback_Test ();
#endif

View file

@ -9,3 +9,15 @@
# error "missing endian definiton"
#endif
--- a/src/linux/ifxos_linux_thread_drv.c
+++ b/src/linux/ifxos_linux_thread_drv.c
@@ -34,7 +34,9 @@
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/completion.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
#include <linux/smp_lock.h>
+#endif
#include <linux/signal.h>

View file

@ -1,6 +1,26 @@
--- a/src/drv_tapi_linux.c
+++ b/src/drv_tapi_linux.c
@@ -146,8 +146,13 @@ static ssize_t ifx_tapi_write(struct fil
@@ -47,7 +47,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h> /* copy_from_user(), ... */
#include <asm/byteorder.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
#include <linux/smp_lock.h> /* lock_kernel() */
+#endif
#include <asm/io.h>
#ifdef LINUX_2_6
@@ -65,7 +67,9 @@
#else
#include <linux/tqueue.h>
#include <linux/sched.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
#include <linux/smp_lock.h> /* lock_kernel() */
+#endif
#endif /* LINUX_2_6 */
#include "drv_tapi.h"
@@ -133,8 +137,13 @@
size_t count, loff_t * ppos);
static ssize_t ifx_tapi_read(struct file * filp, char *buf,
size_t length, loff_t * ppos);
@ -14,7 +34,7 @@
static unsigned int ifx_tapi_poll (struct file *filp, poll_table *table);
#ifdef CONFIG_PROC_FS
@@ -231,7 +236,11 @@ IFX_return_t TAPI_OS_RegisterLLDrv (IFX_
@@ -218,7 +227,11 @@
IFX_char_t *pRegDrvName = IFX_NULL;
IFX_int32_t ret = 0;
@ -26,7 +46,7 @@
{
#ifdef MODULE
tapi_fops.owner = THIS_MODULE;
@@ -239,7 +248,11 @@ IFX_return_t TAPI_OS_RegisterLLDrv (IFX_
@@ -226,7 +239,11 @@
tapi_fops.read = ifx_tapi_read;
tapi_fops.write = ifx_tapi_write;
tapi_fops.poll = ifx_tapi_poll;
@ -38,7 +58,7 @@
tapi_fops.open = ifx_tapi_open;
tapi_fops.release = ifx_tapi_release;
}
@@ -894,8 +907,13 @@ static IFX_uint32_t ifx_tapi_poll (struc
@@ -881,8 +898,13 @@
- 0 and positive values - success
- negative value - ioctl failed
*/
@ -52,6 +72,29 @@
{
TAPI_FD_PRIV_DATA_t *pTapiPriv;
IFX_TAPI_ioctlCtx_t ctx;
@@ -3721,7 +3743,9 @@
kernel lock (lock_kernel()). The lock must be
grabbed before changing the terminate
flag and released after the down() call. */
- lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+ lock_kernel();
+#endif
mb();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
kill_proc(pThrCntrl->tid, SIGKILL, 1);
@@ -3729,8 +3753,10 @@
kill_pid(find_vpid(pThrCntrl->tid), SIGKILL, 1);
#endif
/* release the big kernel lock */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
unlock_kernel();
- wait_for_completion (&pThrCntrl->thrCompletion);
+#endif
+ wait_for_completion (&pThrCntrl->thrCompletion);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
/* Now we are sure the thread is in zombie state.
--- a/src/lib/lib_fifo/lib_fifo.c
+++ b/src/lib/lib_fifo/lib_fifo.c
@@ -41,7 +41,7 @@

View file

@ -33,7 +33,7 @@
#if defined SYSTEM_DANUBE
-#include <asm/ifx/ifx_gpio.h>
+#include <xway/xway.h>
+#include <lantiq_soc.h>
+
#else
#error no system selected
@ -158,7 +158,7 @@
+# define ifx_gptu_timer_free lq_free_timer
+
+
+# define bsp_mask_and_ack_irq lq_mask_and_ack_irq
+# define bsp_mask_and_ack_irq ltq_mask_and_ack_irq
+#else
+# include <asm/ifx/ifx_regs.h>
+# include <asm/ifx/ifx_gptu.h>
@ -443,14 +443,14 @@
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
+IFX_uint32_t ifx_get_cp1_size(IFX_void_t)
+{
+ return 2;
+ return 1;
+}
+
+unsigned int *lq_get_cp1_base(void);
+unsigned int *ltq_get_cp1_base(void);
+
+IFX_uint32_t *ifx_get_cp1_base(IFX_void_t)
+{
+ return lq_get_cp1_base();
+ return ltq_get_cp1_base();
+}
+#endif
+
@ -501,7 +501,7 @@
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28))
+# include <lantiq.h>
+# include <irq.h>
+# include <xway/xway.h>
+# include <lantiq_soc.h>
+# include <gpio.h>
+#define IFXMIPS_MPS_SRAM ((u32 *)(KSEG1 + 0x1F200000))
+#define IFXMIPS_MPS_BASE_ADDR (KSEG1 + 0x1F107000)

View file

@ -1,6 +1,6 @@
--- a/src/drv_vmmc_init.c
+++ b/src/drv_vmmc_init.c
@@ -784,7 +784,7 @@ IFX_int32_t VMMC_TAPI_LL_FW_Start(IFX_TA
@@ -784,7 +784,7 @@
dwld.fwDwld.length = IoInit.pram_size;
/* download firmware */
@ -9,7 +9,7 @@
(IFX_uint32_t) &dwld.fwDwld);
}
@@ -1594,7 +1594,7 @@ IFX_void_t VMMC_DeviceDriverStop(IFX_voi
@@ -1594,7 +1594,7 @@
#ifdef VMMC_DRIVER_UNLOAD_HOOK
if (VDevices[0].nDevState & DS_GPIO_RESERVED)
{
@ -20,7 +20,7 @@
{
--- a/src/mps/drv_mps_vmmc_linux.c
+++ b/src/mps/drv_mps_vmmc_linux.c
@@ -110,7 +110,7 @@ IFX_int32_t ifx_mps_get_status_proc (IFX
@@ -110,7 +110,7 @@
#ifndef __KERNEL__
IFX_int32_t ifx_mps_open (struct inode *inode, struct file *file_p);
IFX_int32_t ifx_mps_close (struct inode *inode, struct file *file_p);
@ -29,7 +29,7 @@
IFX_uint32_t nCmd, IFX_ulong_t arg);
IFX_int32_t ifx_mps_read_mailbox (mps_devices type, mps_message * rw);
IFX_int32_t ifx_mps_write_mailbox (mps_devices type, mps_message * rw);
@@ -171,7 +171,7 @@ IFX_char_t voice_channel_int_name[NUM_VO
@@ -171,7 +171,7 @@
static struct file_operations ifx_mps_fops = {
owner:THIS_MODULE,
poll:ifx_mps_poll,
@ -38,7 +38,7 @@
open:ifx_mps_open,
release:ifx_mps_close
};
@@ -614,7 +614,7 @@ static IFX_uint32_t ifx_mps_poll (struct
@@ -614,7 +614,7 @@
* \return -ENOIOCTLCMD Invalid command
* \ingroup API
*/
@ -47,7 +47,7 @@
IFX_uint32_t nCmd, IFX_ulong_t arg)
{
IFX_int32_t retvalue = -EINVAL;
@@ -629,17 +629,18 @@ IFX_int32_t ifx_mps_ioctl (struct inode
@@ -629,17 +629,18 @@
'mps_devices' enum type, which in fact is [0..8]; So, if inode value is
[0..NUM_VOICE_CHANNEL+1], then we make sure that we are calling from
kernel space. */
@ -71,7 +71,7 @@
{
--- a/src/drv_vmmc_ioctl.c
+++ b/src/drv_vmmc_ioctl.c
@@ -427,18 +427,18 @@ IFX_int32_t VMMC_Dev_Spec_Ioctl (IFX_TAP
@@ -427,18 +427,18 @@
/* MPS driver will do the USR2KERN so just pass on the pointer. */
dwnld_struct.data = (IFX_void_t *)IoInit.pPRAMfw;
@ -95,7 +95,7 @@
case FIO_LASTERR:
--- a/src/mps/drv_mps_vmmc.h
+++ b/src/mps/drv_mps_vmmc.h
@@ -279,7 +279,7 @@ typedef struct
@@ -279,7 +279,7 @@
#include <linux/fs.h>
IFX_int32_t ifx_mps_open (struct inode *inode, struct file *file_p);
IFX_int32_t ifx_mps_close (struct inode *inode, struct file *filp);
@ -104,3 +104,89 @@
IFX_uint32_t nCmd, unsigned long arg);
IFX_int32_t ifx_mps_register_data_callback (mps_devices type, IFX_uint32_t dir,
IFX_void_t (*callback) (mps_devices
--- a/src/drv_vmmc_linux.c
+++ b/src/drv_vmmc_linux.c
@@ -32,7 +32,11 @@
#ifdef LINUX_2_6
#include <linux/version.h>
#ifndef UTS_RELEASE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
+#include <linux/utsrelease.h>
+#else
#include <generated/utsrelease.h>
+#endif
#endif /* UTC_RELEASE */
#undef CONFIG_DEVFS_FS
#endif /* LINUX_2_6 */
--- a/src/mps/drv_mps_vmmc_common.c
+++ b/src/mps/drv_mps_vmmc_common.c
@@ -22,7 +22,11 @@
#undef USE_PLAIN_VOICE_FIRMWARE
#undef PRINT_ON_ERR_INTERRUPT
#undef FAIL_ON_ERR_INTERRUPT
-#include <generated/autoconf.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
+#include <linux/utsrelease.h>
+#else
+#include <generated/utsrelease.h>
+#endif
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -47,8 +51,19 @@
# define ifx_gptu_timer_free lq_free_timer
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
# define bsp_mask_and_ack_irq ltq_mask_and_ack_irq
#else
+extern void ltq_mask_and_ack_irq(struct irq_data *d);
+static void inline bsp_mask_and_ack_irq(int x)
+{
+ struct irq_data d;
+ d.irq = x;
+ ltq_mask_and_ack_irq(&d);
+}
+#endif
+
+#else
# include <asm/ifx/ifx_regs.h>
# include <asm/ifx/ifx_gptu.h>
#endif
@@ -107,7 +122,9 @@
extern mps_mbx_dev *ifx_mps_get_device (mps_devices type);
#ifdef LINUX_2_6
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39))
extern IFX_void_t bsp_mask_and_ack_irq (IFX_uint32_t irq_nr);
+#endif
#else /* */
extern IFX_void_t mask_and_ack_danube_irq (IFX_uint32_t irq_nr);
--- a/src/mps/drv_mps_vmmc_danube.c
+++ b/src/mps/drv_mps_vmmc_danube.c
@@ -16,11 +16,16 @@
/* ============================= */
/* Includes */
/* ============================= */
+#include "linux/version.h"
#include "drv_config.h"
#ifdef SYSTEM_DANUBE /* defined in drv_mps_vmmc_config.h */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
+#include <linux/autoconf.h>
+#else
#include <generated/autoconf.h>
+#endif
/* lib_ifxos headers */
#include "ifx_types.h"
@@ -39,6 +44,7 @@
# include <linux/dma-mapping.h>
+#define LQ_RCU_BASE_ADDR (KSEG1 + LTQ_RCU_BASE_ADDR)
# define LQ_RCU_RST ((u32 *)(LQ_RCU_BASE_ADDR + 0x0010))
#define IFX_RCU_RST_REQ_CPU1 (1 << 3)
# define IFX_RCU_RST_REQ LQ_RCU_RST

View file

@ -0,0 +1,12 @@
--- a/include/linux/atm.h
+++ b/include/linux/atm.h
@@ -139,6 +139,9 @@ struct atm_trafprm {
int min_pcr; /* minimum PCR in cells per second */
int max_cdv; /* maximum CDV in microseconds */
int max_sdu; /* maximum SDU in bytes */
+ int scr; /* sustained rate in cells per second */
+ int mbs; /* maximum burst size (MBS) in cells */
+ int cdv; /* Cell delay varition */
/* extra params for ABR */
unsigned int icr; /* Initial Cell Rate (24-bit) */
unsigned int tbe; /* Transient Buffer Exposure (24-bit) */

View file

@ -0,0 +1,12 @@
--- a/include/linux/atm.h
+++ b/include/linux/atm.h
@@ -139,6 +139,9 @@ struct atm_trafprm {
int min_pcr; /* minimum PCR in cells per second */
int max_cdv; /* maximum CDV in microseconds */
int max_sdu; /* maximum SDU in bytes */
+ int scr; /* sustained rate in cells per second */
+ int mbs; /* maximum burst size (MBS) in cells */
+ int cdv; /* Cell delay varition */
/* extra params for ABR */
unsigned int icr; /* Initial Cell Rate (24-bit) */
unsigned int tbe; /* Transient Buffer Exposure (24-bit) */

View file

@ -10,9 +10,10 @@ ARCH:=mips
BOARD:=lantiq
BOARDNAME:=Lantiq GPON/XWAY
FEATURES:=squashfs jffs2
SUBTARGETS:=falcon xway
SUBTARGETS:=falcon xway ase
LINUX_VERSION:=2.6.37.6
LINUX_VERSION:=2.6.39
#LINUX_VERSION:=2.6.32.33
CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -fno-caller-saves

View file

@ -0,0 +1,15 @@
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
# CONFIG_DM9000 is not set
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_GPIO_BUTTONS is not set
CONFIG_INPUT_POLLDEV=y
# CONFIG_ISDN is not set
CONFIG_LANTIQ_ETOP=y
CONFIG_LANTIQ_MACH_EASY50601=y
CONFIG_SOC_AMAZON_SE=y
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
# CONFIG_SOC_XWAY is not set
# CONFIG_I2C_DESIGNWARE is not set

View file

@ -0,0 +1,39 @@
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_ATH79 is not set
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_GPIO_BUTTONS is not set
CONFIG_INPUT_POLLDEV=y
# CONFIG_ISDN is not set
CONFIG_LANTIQ_ETOP=y
CONFIG_LANTIQ_MACH_EASY50601=y
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
# CONFIG_MTD_LATCH_ADDR is not set
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_PERF_USE_VMALLOC=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_SOC_AMAZON_SE=y
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
# CONFIG_SOC_XWAY is not set
CONFIG_XZ_DEC=y

View file

@ -0,0 +1,6 @@
define Profile/Generic
NAME:=Generic - all boards
PACKAGES:=kmod-leds-gpio button-hotplug
endef
$(eval $(call Profile,Generic))

View file

@ -0,0 +1,10 @@
define Profile/EASY50601
NAME:=EASY50601
PACKAGES:= kmod-usb-core kmod-usb-dwc-otg kmod-leds-gpio
endef
define Profile/EASY50601/Description
Lantiq EASY50601 evalkit
endef
$(eval $(call Profile,EASY50601))

View file

@ -0,0 +1,10 @@
ARCH:=mips
SUBTARGET:=ase
BOARDNAME:=Amazon-SE
FEATURES:=squashfs jffs2 atm
DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app
define Target/Description
Lantiq ASE
endef

View file

@ -1,4 +1,4 @@
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K stop
ttyS0::askfirst:/bin/ash --login
ttyS1::askfirst:/bin/ash --login
ttyLTQ0::askfirst:/bin/ash --login
ttyLTQ1::askfirst:/bin/ash --login

View file

@ -0,0 +1,149 @@
CONFIG_32BIT=y
# CONFIG_64BIT is not set
# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
# CONFIG_AR7 is not set
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
CONFIG_BITREVERSE=y
CONFIG_BOOT_RAW=y
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
CONFIG_CEVT_R4K=y
CONFIG_CEVT_R4K_LIB=y
CONFIG_CFG80211_DEFAULT_PS_VALUE=0
CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_CPU_CAVIUM_OCTEON is not set
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
# CONFIG_CPU_LOONGSON2E is not set
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
CONFIG_CPU_MIPSR2=y
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R5500 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_VR41XX is not set
CONFIG_CSRC_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_EARLY_PRINTK=y
# CONFIG_FSNOTIFY is not set
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
CONFIG_IFX_UDP_REDIRECT=y
CONFIG_IMAGE_CMDLINE_HACK=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQ_CPU=y
CONFIG_LANTIQ=y
CONFIG_LANTIQ_WDT=y
CONFIG_LEDS_GPIO=y
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_MACH_LOONGSON is not set
# CONFIG_MACH_TX39XX is not set
# CONFIG_MACH_TX49XX is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_MIKROTIK_RB532 is not set
CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_MACHINE=y
# CONFIG_MIPS_MALTA is not set
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_LANTIQ=y
CONFIG_MTD_UIMAGE_SPLIT=y
CONFIG_NLS=y
# CONFIG_NO_IOPORT is not set
# CONFIG_NXP_STB220 is not set
# CONFIG_NXP_STB225 is not set
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PHYLIB=y
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
CONFIG_SCHED_OMIT_FRAME_POINTER=y
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_LANTIQ=y
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP28 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_SWARM is not set
CONFIG_SWAP_IO_SPACE=y
CONFIG_SWCONFIG=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_TRAD_SIGNALS=y
# CONFIG_TREE_PREEMPT_RCU is not set
CONFIG_TREE_RCU=y
CONFIG_ZONE_DMA_FLAG=0

View file

@ -5,28 +5,26 @@ CONFIG_32BIT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_ARCH_SUPPORTS_OPROFILE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
# CONFIG_AUTO_IRQ_AFFINITY is not set
# CONFIG_BCM47XX is not set
# CONFIG_BCM63XX is not set
CONFIG_BITREVERSE=y
CONFIG_BKL=y
CONFIG_BOOT_RAW=y
# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
CONFIG_CEVT_R4K=y
CONFIG_CEVT_R4K_LIB=y
CONFIG_CFG80211_DEFAULT_PS_VALUE=0
CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_CPU_CAVIUM_OCTEON is not set
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
# CONFIG_CPU_LOONGSON2E is not set
# CONFIG_CPU_LOONGSON2F is not set
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
@ -54,63 +52,43 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CSRC_R4K=y
CONFIG_CSRC_R4K_LIB=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DEVPORT=y
# CONFIG_DM9000 is not set
CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_EARLY_PRINTK=y
# CONFIG_FSNOTIFY is not set
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_GPIO=y
# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
# CONFIG_GENERIC_PENDING_IRQ is not set
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HARDIRQS_SW_RESEND is not set
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
# CONFIG_HAVE_IDE is not set
CONFIG_HAVE_IDE=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
# CONFIG_HAVE_SPARSE_IRQ is not set
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_I2C_FALCON is not set
CONFIG_IFX_UDP_REDIRECT=y
CONFIG_IMAGE_CMDLINE_HACK=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQ_CPU=y
# CONFIG_IRQ_PER_CPU is not set
CONFIG_LANTIQ=y
CONFIG_LANTIQ_WDT=y
CONFIG_LEDS_GPIO=y
CONFIG_LOONGSON_UART_BASE=y
# CONFIG_MACH_ALCHEMY is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_MACH_LOONGSON is not set
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MACH_TX39XX is not set
# CONFIG_MACH_TX49XX is not set
# CONFIG_MACH_VR41XX is not set
@ -130,28 +108,19 @@ CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_LANTIQ=y
CONFIG_MTD_UIMAGE_SPLIT=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NLS=y
# CONFIG_NO_IOPORT is not set
# CONFIG_NXP_STB220 is not set
# CONFIG_NXP_STB225 is not set
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
# CONFIG_PMC_MSP is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
# CONFIG_POWERTV is not set
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
CONFIG_SCHED_OMIT_FRAME_POINTER=y
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250 is not set
# CONFIG_SERIAL_8250_EXTENDED is not set
CONFIG_SERIAL_LANTIQ=y
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
@ -165,7 +134,6 @@ CONFIG_SERIAL_LANTIQ=y
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_SWARM is not set
CONFIG_SOC_LANTIQ=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_SWCONFIG=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
@ -175,8 +143,6 @@ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
# CONFIG_TC35815 is not set
CONFIG_TINY_RCU=y
CONFIG_TRAD_SIGNALS=y
# CONFIG_TREE_PREEMPT_RCU is not set
CONFIG_TREE_RCU=y

View file

@ -1,9 +0,0 @@
#!/usr/bin/python
from sys import stdin, stdout
while True:
c = stdin.read(2)
if len(c) < 2:
break
n1, n2 = ord(c[0]), ord(c[1])
stdout.write(chr(((n2 & 15) << 4) + ((n2 & 240) >> 4)))
stdout.write(chr(((n1 & 15) << 4) + ((n1 & 240) >> 4)))

View file

@ -1,44 +0,0 @@
#!/bin/sh
DIR="$1/"
FILE="$1/$2"
echo "This tool downloads the arcor a800 firmware release and extracts the voip firmware for the danube."
echo "Please only do so if it is legal in your country"
[ ! -f ${FILE} ] && {
echo ${FILE} is missing
exit 1
}
[ -f ${DIR}/ifxmips_fw_decodev2.tar.bz2 -a ! -f ${DIR}voip_coef.bin ] && {
[ ! -f ${DIR}decode_ifx_fw && -f ${DIR}ifxmips_fw_decodev2.tar.bz2 ] && {
tar xjf ${DIR}ifxmips_fw_decodev2.tar.bz2 ifxmips_fw_decode/decode.c -O > ${DIR}decode.c
gcc -o ${DIR}decode_ifx_fw ${DIR}decode.c
}
[ ! -f ${DIR}decode_ifx_fw ] && {
[ ! -f ${DIR}voip_coef.lzma ] && {
${DIR}decode_ifx_fw $FILE ${DIR}voip_coef.lzma
}
lzma d ${DIR}voip_coef.lzma ${DIR}voip_coef.bin
}
}
[ ! -f ${DIR}dsl_a.bin ] && {
dd if=${FILE} of=${DIR}dsl1.lzma bs=1 skip=2168832 count=150724
lzma d ${DIR}dsl2.lzma ${DIR}dsl_a.bin
}
[ ! -f ${DIR}dsl_b.bin ] && {
dd if=${FILE} of=${DIR}dsl2.lzma bs=1 skip=2320384 count=148343
lzma d ${DIR}dsl1.lzma ${DIR}dsl_b.bin
}
[ ! -f ${DIR}voip.bin ] && {
dd if=${FILE} of=${DIR}voip.lzma bs=1 skip=2468864 count=452105
lzma d ${DIR}voip.lzma ${DIR}voip.bin
}
exit 0
# get lzma offsets
# hexdump -C arcor_A800_452CPW_FW_1.02.206\(20081201\).bin | grep "5d 00 00 80"
# hexdump -C arcor_A800_452CPW_FW_1.02.206\(20081201\).bin | grep "00 d5 08 00"

View file

@ -0,0 +1,33 @@
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
# CONFIG_CRYPTO is not set
CONFIG_DM9000=y
CONFIG_DM9000_DEBUGLEVEL=4
CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_DESIGNWARE is not set
CONFIG_I2C_FALCON=y
CONFIG_IFX_VPE_CACHE_SPLIT=y
CONFIG_IFX_VPE_EXT=y
CONFIG_LANTIQ_MACH_95C3AM1=y
CONFIG_LANTIQ_MACH_EASY98000=y
CONFIG_LANTIQ_MACH_EASY98020=y
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MIPS_MT=y
# CONFIG_MIPS_VPE_APSP_API is not set
CONFIG_MIPS_VPE_LOADER=y
CONFIG_MIPS_VPE_LOADER_TOM=y
CONFIG_MTD_M25P80=y
CONFIG_MTSCHED=y
# CONFIG_PERFCTRS is not set
# CONFIG_SOC_AMAZON_SE is not set
CONFIG_SOC_FALCON=y
# CONFIG_SOC_TYPE_XWAY is not set
# CONFIG_SOC_XWAY is not set
CONFIG_SPI=y
# CONFIG_SPI_BITBANG is not set
CONFIG_SPI_FALCON=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y
# CONFIG_SPI_SPIDEV is not set

View file

@ -1,31 +1,63 @@
# CONFIG_ALTERA_STAPL is not set
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
# CONFIG_ATH79 is not set
CONFIG_CPU_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
# CONFIG_CRYPTO is not set
CONFIG_DM9000=y
CONFIG_DM9000_DEBUGLEVEL=4
CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y
CONFIG_HAVE_IDE=y
CONFIG_HW_HAS_PCI=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_FALCON=y
# CONFIG_I2C_PXA_PCI is not set
CONFIG_IFX_VPE_CACHE_SPLIT=y
CONFIG_IFX_VPE_EXT=y
CONFIG_LANTIQ_MACH_95C3AM1=y
CONFIG_LANTIQ_MACH_EASY98000=y
CONFIG_LANTIQ_MACH_EASY98020=y
CONFIG_LANTIQ_PROM_ASC0=y
# CONFIG_LANTIQ_PROM_ASC1 is not set
# CONFIG_LEDS_LM3530 is not set
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MACH_NO_WESTBRIDGE=y
# CONFIG_MFD_MAX8997 is not set
# CONFIG_MFD_WL1273_CORE is not set
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
CONFIG_MIPS_MT=y
# CONFIG_MIPS_VPE_APSP_API is not set
CONFIG_MIPS_VPE_LOADER=y
CONFIG_MIPS_VPE_LOADER_TOM=y
# CONFIG_MTD_LATCH_ADDR is not set
CONFIG_MTD_M25P80=y
CONFIG_MTSCHED=y
# CONFIG_PCI is not set
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
# CONFIG_PERFCTRS is not set
CONFIG_SOC_LANTIQ_FALCON=y
# CONFIG_SOC_LANTIQ_XWAY is not set
CONFIG_PERF_USE_VMALLOC=y
# CONFIG_PREEMPT_RCU is not set
# CONFIG_QUOTACTL is not set
# CONFIG_SOC_AMAZON_SE is not set
CONFIG_SOC_FALCON=y
# CONFIG_SOC_TYPE_XWAY is not set
# CONFIG_SOC_XWAY is not set
CONFIG_SPI=y
# CONFIG_SPI_BITBANG is not set
CONFIG_SPI_FALCON=y
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_MASTER=y
# CONFIG_TPS6105X is not set
CONFIG_XZ_DEC=y

View file

@ -9,8 +9,9 @@ include $(INCLUDE_DIR)/image.mk
JFFS2_BLOCKSIZE = 64k 128k 256k
xway_cmdline=-console=ttyS1,115200 rootfstype=squashfs,jffs2
falcon_cmdline=-console=ttyS0,115200 rootfstype=squashfs,jffs2
ase_cmdline=-console=ttyLTQ1,115200 rootfstype=squashfs,jffs2
xway_cmdline=-console=ttyLTQ1,115200 rootfstype=squashfs,jffs2
falcon_cmdline=-console=ttyLTQ0,115200 rootfstype=squashfs,jffs2
define CompressLzma
$(STAGING_DIR_HOST)/bin/lzma e $(1) $(2)
@ -184,6 +185,27 @@ define Image/Build/Profile/Generic
endef
endif
ifeq ($(CONFIG_TARGET_lantiq_ase),y)
define Image/BuildKernel/Profile/EASY50601
$(call Image/BuildKernel/Template,EASY50601,$(ase_cmdline))
endef
define Image/Build/Profile/EASY50601
$(call Image/Build/$(1),$(1),EASY50601)
endef
define Image/BuildKernel/Profile/Generic
$(call Image/BuildKernel/Template,EASY50601,$(ase_cmdline))
$(call Image/BuildKernel/Template,NONE)
endef
define Image/Build/Profile/Generic
$(call Image/Build/$(1),$(1),EASY50601)
$(call Image/Build/$(1),$(1),NONE)
$(CP) $(KDIR)/root.$(1) $(BIN_DIR)/$(IMG_PREFIX)-$(1).rootfs
endef
endif
define Image/BuildKernel
$(call Image/BuildKernel/Profile/$(PROFILE))
endef

View file

@ -0,0 +1,898 @@
From 9e0235e97ea2617beaacaa16ab5f0b9e75f4680e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2011 09:27:47 +0200
Subject: [PATCH 01/13] MIPS: Lantiq: Add initial support for Lantiq SoCs
Add initial support for Mips based SoCs made by Lantiq. This series will add
support for the XWAY family.
The series allows booting a minimal system using a initramfs or NOR. Missing
drivers and support for Amazon and GPON family will be provided in a later
series.
[Ralf: Remove some cargo cult programming and fixed formatting.]
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2252/
Patchwork: https://patchwork.linux-mips.org/patch/2371/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 17 ++
arch/mips/include/asm/mach-lantiq/lantiq.h | 63 ++++++
arch/mips/include/asm/mach-lantiq/war.h | 24 ++
arch/mips/lantiq/Makefile | 9 +
arch/mips/lantiq/Platform | 7 +
arch/mips/lantiq/clk.c | 140 ++++++++++++
arch/mips/lantiq/clk.h | 18 ++
arch/mips/lantiq/early_printk.c | 33 +++
arch/mips/lantiq/irq.c | 326 ++++++++++++++++++++++++++++
arch/mips/lantiq/prom.c | 71 ++++++
arch/mips/lantiq/prom.h | 24 ++
arch/mips/lantiq/setup.c | 41 ++++
13 files changed, 774 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/war.h
create mode 100644 arch/mips/lantiq/Makefile
create mode 100644 arch/mips/lantiq/Platform
create mode 100644 arch/mips/lantiq/clk.c
create mode 100644 arch/mips/lantiq/clk.h
create mode 100644 arch/mips/lantiq/early_printk.c
create mode 100644 arch/mips/lantiq/irq.c
create mode 100644 arch/mips/lantiq/prom.c
create mode 100644 arch/mips/lantiq/prom.h
create mode 100644 arch/mips/lantiq/setup.c
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -174,6 +174,23 @@
Members include the Acer PICA, MIPS Magnum 4000, MIPS Millennium and
Olivetti M700-10 workstations.
+config LANTIQ
+ bool "Lantiq based platforms"
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select CEVT_R4K
+ select CSRC_R4K
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_MULTITHREADING
+ select SYS_HAS_EARLY_PRINTK
+ select ARCH_REQUIRE_GPIOLIB
+ select SWAP_IO_SPACE
+ select BOOT_RAW
+ select HAVE_CLK
+
config LASAT
bool "LASAT Networks platforms"
select CEVT_R4K
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
@@ -0,0 +1,63 @@
+/*
+ * 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>
+ */
+#ifndef _LANTIQ_H__
+#define _LANTIQ_H__
+
+#include <linux/irq.h>
+
+/* generic reg access functions */
+#define ltq_r32(reg) __raw_readl(reg)
+#define ltq_w32(val, reg) __raw_writel(val, reg)
+#define ltq_w32_mask(clear, set, reg) \
+ ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg)
+#define ltq_r8(reg) __raw_readb(reg)
+#define ltq_w8(val, reg) __raw_writeb(val, reg)
+
+/* register access macros for EBU and CGU */
+#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
+#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
+#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y))
+#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x))
+
+extern __iomem void *ltq_ebu_membase;
+extern __iomem void *ltq_cgu_membase;
+
+extern unsigned int ltq_get_cpu_ver(void);
+extern unsigned int ltq_get_soc_type(void);
+
+/* clock speeds */
+#define CLOCK_60M 60000000
+#define CLOCK_83M 83333333
+#define CLOCK_111M 111111111
+#define CLOCK_133M 133333333
+#define CLOCK_167M 166666667
+#define CLOCK_200M 200000000
+#define CLOCK_266M 266666666
+#define CLOCK_333M 333333333
+#define CLOCK_400M 400000000
+
+/* spinlock all ebu i/o */
+extern spinlock_t ebu_lock;
+
+/* some irq helpers */
+extern void ltq_disable_irq(unsigned int irq);
+extern void ltq_mask_and_ack_irq(unsigned int irq);
+extern void ltq_enable_irq(unsigned int irq);
+
+/* find out what caused the last cpu reset */
+extern int ltq_reset_cause(void);
+#define LTQ_RST_CAUSE_WDTRST 0x20
+
+#define IOPORT_RESOURCE_START 0x10000000
+#define IOPORT_RESOURCE_END 0xffffffff
+#define IOMEM_RESOURCE_START 0x10000000
+#define IOMEM_RESOURCE_END 0xffffffff
+#define LTQ_FLASH_START 0x10000000
+#define LTQ_FLASH_MAX 0x04000000
+
+#endif
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/war.h
@@ -0,0 +1,24 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H
+#define __ASM_MIPS_MACH_LANTIQ_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif
--- /dev/null
+++ b/arch/mips/lantiq/Makefile
@@ -0,0 +1,9 @@
+# Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+#
+# 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.
+
+obj-y := irq.o setup.o clk.o prom.o
+
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
--- /dev/null
+++ b/arch/mips/lantiq/Platform
@@ -0,0 +1,7 @@
+#
+# Lantiq
+#
+
+platform-$(CONFIG_LANTIQ) += lantiq/
+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+load-$(CONFIG_LANTIQ) = 0xffffffff80002000
--- /dev/null
+++ b/arch/mips/lantiq/clk.c
@@ -0,0 +1,144 @@
+/*
+ * 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 Thomas Langer <thomas.langer@lantiq.com>
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+#include "clk.h"
+
+struct clk {
+ const char *name;
+ unsigned long rate;
+ unsigned long (*get_rate) (void);
+};
+
+static struct clk *cpu_clk;
+static int cpu_clk_cnt;
+
+/* lantiq socs have 3 static clocks */
+static struct clk cpu_clk_generic[] = {
+ {
+ .name = "cpu",
+ .get_rate = ltq_get_cpu_hz,
+ }, {
+ .name = "fpi",
+ .get_rate = ltq_get_fpi_hz,
+ }, {
+ .name = "io",
+ .get_rate = ltq_get_io_region_clock,
+ },
+};
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+static struct resource ltq_cgu_resource = {
+ .name = "cgu",
+ .start = LTQ_CGU_BASE_ADDR,
+ .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+/* remapped clock register range */
+void __iomem *ltq_cgu_membase;
+#endif
+
+void clk_init(void)
+{
+ cpu_clk = cpu_clk_generic;
+ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
+}
+
+static inline int clk_good(struct clk *clk)
+{
+ return clk && !IS_ERR(clk);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (unlikely(!clk_good(clk)))
+ return 0;
+
+ if (clk->rate != 0)
+ return clk->rate;
+
+ if (clk->get_rate != NULL)
+ return clk->get_rate();
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ int i;
+
+ for (i = 0; i < cpu_clk_cnt; i++)
+ if (!strcmp(id, cpu_clk[i].name))
+ return &cpu_clk[i];
+ BUG();
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ /* not used */
+}
+EXPORT_SYMBOL(clk_put);
+
+static inline u32 ltq_get_counter_resolution(void)
+{
+ u32 res;
+
+ __asm__ __volatile__(
+ ".set push\n"
+ ".set mips32r2\n"
+ "rdhwr %0, $3\n"
+ ".set pop\n"
+ : "=&r" (res)
+ : /* no input */
+ : "memory");
+
+ return res;
+}
+
+void __init plat_time_init(void)
+{
+ struct clk *clk;
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+ if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0)
+ panic("Failed to insert cgu memory\n");
+
+ if (request_mem_region(ltq_cgu_resource.start,
+ resource_size(&ltq_cgu_resource), "cgu") < 0)
+ panic("Failed to request cgu memory\n");
+
+ ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
+ resource_size(&ltq_cgu_resource));
+ if (!ltq_cgu_membase) {
+ pr_err("Failed to remap cgu memory\n");
+ unreachable();
+ }
+#endif
+ clk = clk_get(0, "cpu");
+ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
+ write_c0_compare(read_c0_count());
+ clk_put(clk);
+}
--- /dev/null
+++ b/arch/mips/lantiq/clk.h
@@ -0,0 +1,18 @@
+/*
+ * 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>
+ */
+
+#ifndef _LTQ_CLK_H__
+#define _LTQ_CLK_H__
+
+extern void clk_init(void);
+
+extern unsigned long ltq_get_cpu_hz(void);
+extern unsigned long ltq_get_fpi_hz(void);
+extern unsigned long ltq_get_io_region_clock(void);
+
+#endif
--- /dev/null
+++ b/arch/mips/lantiq/early_printk.c
@@ -0,0 +1,37 @@
+/*
+ * 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/cpu.h>
+
+#include <lantiq.h>
+#include <lantiq_soc.h>
+
+/* no ioremap possible at this early stage, lets use KSEG1 instead */
+#ifdef CONFIG_SOC_FALCON
+#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC0_BASE_ADDR)
+#else
+#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
+#endif
+#define ASC_BUF 1024
+#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
+#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
+#define TXMASK 0x3F00
+#define TXOFFSET 8
+
+void prom_putchar(char c)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
+ if (c == '\n')
+ ltq_w32('\r', LTQ_ASC_TBUF);
+ ltq_w32(c, LTQ_ASC_TBUF);
+ local_irq_restore(flags);
+}
--- /dev/null
+++ b/arch/mips/lantiq/irq.c
@@ -0,0 +1,353 @@
+/*
+ * 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>
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+/* register definitions */
+#define LTQ_ICU_IM0_ISR 0x0000
+#define LTQ_ICU_IM0_IER 0x0008
+#define LTQ_ICU_IM0_IOSR 0x0010
+#define LTQ_ICU_IM0_IRSR 0x0018
+#define LTQ_ICU_IM0_IMR 0x0020
+#define LTQ_ICU_IM1_ISR 0x0028
+#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+
+#define LTQ_EIU_EXIN_C 0x0000
+#define LTQ_EIU_EXIN_INIC 0x0004
+#define LTQ_EIU_EXIN_INEN 0x000C
+
+/* irq numbers used by the external interrupt unit (EIU) */
+#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
+#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
+#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
+#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
+#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
+#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
+#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
+
+#define MAX_EIU 6
+
+/* irqs generated by device attached to the EBU need to be acked in
+ * a special manner
+ */
+#define LTQ_ICU_EBU_IRQ 22
+
+#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y))
+#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x))
+
+static unsigned short ltq_eiu_irq[MAX_EIU] = {
+ LTQ_EIU_IR0,
+ LTQ_EIU_IR1,
+ LTQ_EIU_IR2,
+ LTQ_EIU_IR3,
+ LTQ_EIU_IR4,
+ LTQ_EIU_IR5,
+};
+
+static void __iomem *ltq_eiu_membase;
+
+static struct resource ltq_eiu_resource = {
+ .name = "eiu",
+ .start = LTQ_EIU_BASE_ADDR,
+ .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+#endif
+
+static struct resource ltq_icu_resource = {
+ .name = "icu",
+ .start = LTQ_ICU_BASE_ADDR,
+ .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y))
+#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x))
+
+static void __iomem *ltq_icu_membase;
+
+void
+ltq_disable_irq(unsigned int irq_nr)
+{
+ u32 ier = LTQ_ICU_IM0_IER;
+
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+}
+
+void
+ltq_mask_and_ack_irq(unsigned int irq_nr)
+{
+ u32 ier = LTQ_ICU_IM0_IER;
+ u32 isr = LTQ_ICU_IM0_ISR;
+
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+ ltq_icu_w32((1 << irq_nr), isr);
+}
+EXPORT_SYMBOL(ltq_mask_and_ack_irq);
+
+static void
+ltq_ack_irq(unsigned int irq_nr)
+{
+ u32 isr = LTQ_ICU_IM0_ISR;
+
+ irq_nr -= INT_NUM_IRQ0;
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32((1 << irq_nr), isr);
+}
+
+void
+ltq_enable_irq(unsigned int irq_nr)
+{
+ u32 ier = LTQ_ICU_IM0_IER;
+
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
+}
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+static unsigned int
+ltq_startup_eiu_irq(unsigned int irq)
+{
+ int i;
+
+ ltq_enable_irq(irq);
+ for (i = 0; i < MAX_EIU; i++) {
+ if (irq == ltq_eiu_irq[i]) {
+ /* low level - we should really handle set_type */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | (0x6 << (i * 4)),
+ LTQ_EIU_EXIN_C);
+ /* clear all pending */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i),
+ LTQ_EIU_EXIN_INIC);
+ /* enable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i),
+ LTQ_EIU_EXIN_INEN);
+ break;
+ }
+ }
+ return 0;
+}
+
+static void
+ltq_shutdown_eiu_irq(unsigned int irq)
+{
+ int i;
+
+ ltq_disable_irq(irq);
+ for (i = 0; i < MAX_EIU; i++) {
+ if (irq == ltq_eiu_irq[i]) {
+ /* disable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
+ LTQ_EIU_EXIN_INEN);
+ break;
+ }
+ }
+}
+#endif
+
+static void
+ltq_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ ltq_enable_irq(irq);
+}
+
+static struct irq_chip
+ltq_irq_type = {
+ "ltq_irq",
+ .enable = ltq_enable_irq,
+ .disable = ltq_disable_irq,
+ .unmask = ltq_enable_irq,
+ .ack = ltq_ack_irq,
+ .mask = ltq_disable_irq,
+ .mask_ack = ltq_mask_and_ack_irq,
+ .end = ltq_end_irq,
+};
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+static struct irq_chip
+ltq_eiu_type = {
+ "ltq_eiu_irq",
+ .startup = ltq_startup_eiu_irq,
+ .shutdown = ltq_shutdown_eiu_irq,
+ .enable = ltq_enable_irq,
+ .disable = ltq_disable_irq,
+ .unmask = ltq_enable_irq,
+ .ack = ltq_ack_irq,
+ .mask = ltq_disable_irq,
+ .mask_ack = ltq_mask_and_ack_irq,
+ .end = ltq_end_irq,
+};
+#endif
+
+static void ltq_hw_irqdispatch(int module)
+{
+ u32 irq;
+
+ irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
+ if (irq == 0)
+ return;
+
+ /* silicon bug causes only the msb set to 1 to be valid. all
+ * other bits might be bogus
+ */
+ irq = __fls(irq);
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+ /* if this is a EBU irq, we need to ack it or get a deadlock */
+ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
+ LTQ_EBU_PCC_ISTAT);
+#endif
+}
+
+#define DEFINE_HWx_IRQDISPATCH(x) \
+ static void ltq_hw ## x ## _irqdispatch(void) \
+ { \
+ ltq_hw_irqdispatch(x); \
+ }
+DEFINE_HWx_IRQDISPATCH(0)
+DEFINE_HWx_IRQDISPATCH(1)
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+
+static void ltq_hw5_irqdispatch(void)
+{
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ unsigned int i;
+
+ if (pending & CAUSEF_IP7) {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ goto out;
+ } else {
+ for (i = 0; i < 5; i++) {
+ if (pending & (CAUSEF_IP2 << i)) {
+ ltq_hw_irqdispatch(i);
+ goto out;
+ }
+ }
+ }
+ pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+
+out:
+ return;
+}
+
+static struct irqaction cascade = {
+ .handler = no_action,
+ .flags = IRQF_DISABLED,
+ .name = "cascade",
+};
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ if (insert_resource(&iomem_resource, &ltq_icu_resource) < 0)
+ panic("Failed to insert icu memory\n");
+
+ if (request_mem_region(ltq_icu_resource.start,
+ resource_size(&ltq_icu_resource), "icu") < 0)
+ panic("Failed to request icu memory\n");
+
+ ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start,
+ resource_size(&ltq_icu_resource));
+ if (!ltq_icu_membase)
+ panic("Failed to remap icu memory\n");
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+ if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
+ panic("Failed to insert eiu memory\n");
+
+ if (request_mem_region(ltq_eiu_resource.start,
+ resource_size(&ltq_eiu_resource), "eiu") < 0)
+ panic("Failed to request eiu memory\n");
+
+ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
+ resource_size(&ltq_eiu_resource));
+ if (!ltq_eiu_membase)
+ panic("Failed to remap eiu memory\n");
+#endif
+ /* make sure all irqs are turned off by default */
+ for (i = 0; i < 5; i++)
+ ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
+
+ /* clear all possibly pending interrupts */
+ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
+
+ mips_cpu_irq_init();
+
+ for (i = 2; i <= 6; i++)
+ setup_irq(i, &cascade);
+
+ if (cpu_has_vint) {
+ pr_info("Setting up vectored interrupts\n");
+ set_vi_handler(2, ltq_hw0_irqdispatch);
+ set_vi_handler(3, ltq_hw1_irqdispatch);
+ set_vi_handler(4, ltq_hw2_irqdispatch);
+ set_vi_handler(5, ltq_hw3_irqdispatch);
+ set_vi_handler(6, ltq_hw4_irqdispatch);
+ set_vi_handler(7, ltq_hw5_irqdispatch);
+ }
+
+ for (i = INT_NUM_IRQ0;
+ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+#ifdef CONFIG_SOC_TYPE_XWAY
+ if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || (i == LTQ_EIU_IR2))
+ set_irq_chip_and_handler(i, &ltq_eiu_type, handle_level_irq);
+ /* EIU3-5 only exist on ar9 and vr9 */
+ else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) ||
+ (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9()))
+ set_irq_chip_and_handler(i, &ltq_eiu_type, handle_level_irq);
+ else
+#endif
+ set_irq_chip_and_handler(i, &ltq_irq_type, handle_level_irq);
+
+#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
+ IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+#else
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+#endif
+ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
+}
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
--- /dev/null
+++ b/arch/mips/lantiq/prom.c
@@ -0,0 +1,71 @@
+/*
+ * 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/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq.h>
+
+#include "prom.h"
+#include "clk.h"
+
+static struct ltq_soc_info soc_info;
+
+unsigned int ltq_get_cpu_ver(void)
+{
+ return soc_info.rev;
+}
+EXPORT_SYMBOL(ltq_get_cpu_ver);
+
+unsigned int ltq_get_soc_type(void)
+{
+ return soc_info.type;
+}
+EXPORT_SYMBOL(ltq_get_soc_type);
+
+const char *get_system_type(void)
+{
+ return soc_info.sys_type;
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+static void __init prom_init_cmdline(void)
+{
+ int argc = fw_arg0;
+ char **argv = (char **) KSEG1ADDR(fw_arg1);
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ char *p = (char *) KSEG1ADDR(argv[i]);
+
+ if (p && *p) {
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ }
+ }
+}
+
+void __init prom_init(void)
+{
+ struct clk *clk;
+
+ ltq_soc_detect(&soc_info);
+ clk_init();
+ clk = clk_get(0, "cpu");
+ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d",
+ soc_info.name, soc_info.rev);
+ clk_put(clk);
+ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+ pr_info("SoC: %s\n", soc_info.sys_type);
+ prom_init_cmdline();
+}
--- /dev/null
+++ b/arch/mips/lantiq/prom.h
@@ -0,0 +1,24 @@
+/*
+ * 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>
+ */
+
+#ifndef _LTQ_PROM_H__
+#define _LTQ_PROM_H__
+
+#define LTQ_SYS_TYPE_LEN 0x100
+
+struct ltq_soc_info {
+ unsigned char *name;
+ unsigned int rev;
+ unsigned int partnum;
+ unsigned int type;
+ unsigned char sys_type[LTQ_SYS_TYPE_LEN];
+};
+
+extern void ltq_soc_detect(struct ltq_soc_info *i);
+
+#endif
--- /dev/null
+++ b/arch/mips/lantiq/setup.c
@@ -0,0 +1,41 @@
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+
+#include <lantiq_soc.h>
+
+void __init plat_mem_setup(void)
+{
+ /* assume 16M as default incase uboot fails to pass proper ramsize */
+ unsigned long memsize = 16;
+ char **envp = (char **) KSEG1ADDR(fw_arg2);
+
+ ioport_resource.start = IOPORT_RESOURCE_START;
+ ioport_resource.end = IOPORT_RESOURCE_END;
+ iomem_resource.start = IOMEM_RESOURCE_START;
+ iomem_resource.end = IOMEM_RESOURCE_END;
+
+ set_io_port_base((unsigned long) KSEG1);
+
+ while (*envp) {
+ char *e = (char *)KSEG1ADDR(*envp);
+ if (!strncmp(e, "memsize=", 8)) {
+ e += 8;
+ if (strict_strtoul(e, 0, &memsize))
+ pr_warn("bad memsize specified\n");
+ }
+ envp++;
+ }
+ memsize *= 1024 * 1024;
+ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+}

View file

@ -0,0 +1,546 @@
From 08127ed36bad367903591bbf0f244179683ccb28 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2011 09:27:49 +0200
Subject: [PATCH 03/13] MIPS: Lantiq: Add PCI controller support.
The Lantiq family of SoCs have a EBU (External Bus Unit). This patch adds
the driver that allows us to use the EBU as a PCI controller. In order for
PCI to work the EBU is set to endianess swap all the data. In addition we
need to make use of SWAP_IO_SPACE for device->host DMA to work.
The clock of the PCI works in several modes (internal/external). If this
is not configured correctly the SoC will hang.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2250/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
.../mips/include/asm/mach-lantiq/lantiq_platform.h | 46 +++
arch/mips/pci/Makefile | 1 +
arch/mips/pci/ops-lantiq.c | 116 ++++++++
arch/mips/pci/pci-lantiq.c | 297 ++++++++++++++++++++
arch/mips/pci/pci-lantiq.h | 18 ++
5 files changed, 478 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h
create mode 100644 arch/mips/pci/ops-lantiq.c
create mode 100644 arch/mips/pci/pci-lantiq.c
create mode 100644 arch/mips/pci/pci-lantiq.h
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
new file mode 100644
index 0000000..1f1dba6
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -0,0 +1,46 @@
+/*
+ * 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>
+ */
+
+#ifndef _LANTIQ_PLATFORM_H__
+#define _LANTIQ_PLATFORM_H__
+
+#include <linux/mtd/partitions.h>
+
+/* struct used to pass info to the pci core */
+enum {
+ PCI_CLOCK_INT = 0,
+ PCI_CLOCK_EXT
+};
+
+#define PCI_EXIN0 0x0001
+#define PCI_EXIN1 0x0002
+#define PCI_EXIN2 0x0004
+#define PCI_EXIN3 0x0008
+#define PCI_EXIN4 0x0010
+#define PCI_EXIN5 0x0020
+#define PCI_EXIN_MAX 6
+
+#define PCI_GNT1 0x0040
+#define PCI_GNT2 0x0080
+#define PCI_GNT3 0x0100
+#define PCI_GNT4 0x0200
+
+#define PCI_REQ1 0x0400
+#define PCI_REQ2 0x0800
+#define PCI_REQ3 0x1000
+#define PCI_REQ4 0x2000
+#define PCI_REQ_SHIFT 10
+#define PCI_REQ_MASK 0xf
+
+struct ltq_pci_data {
+ int clock;
+ int gpio;
+ int irq[16];
+};
+
+#endif
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index f0d5329..4df8799 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
+obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c
new file mode 100644
index 0000000..1f2afb5
--- /dev/null
+++ b/arch/mips/pci/ops-lantiq.c
@@ -0,0 +1,116 @@
+/*
+ * 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/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/addrspace.h>
+#include <linux/vmalloc.h>
+
+#include <lantiq_soc.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BUSNUM_SHF 16
+#define LTQ_PCI_CFG_DEVNUM_SHF 11
+#define LTQ_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, unsigned int where, u32 *data)
+{
+ unsigned long cfg_base;
+ unsigned long flags;
+ u32 temp;
+
+ /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the
+ SoC itself */
+ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78)
+ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68))
+ return 1;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+ cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn <<
+ LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3);
+
+ /* Perform access */
+ if (access_type == PCI_ACCESS_WRITE) {
+ ltq_w32(swab32(*data), ((u32 *)cfg_base));
+ } else {
+ *data = ltq_r32(((u32 *)(cfg_base)));
+ *data = swab32(*data);
+ }
+ wmb();
+
+ /* clean possible Master abort */
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+ cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
+ temp = ltq_r32(((u32 *)(cfg_base)));
+ temp = swab32(temp);
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+ cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
+ ltq_w32(temp, ((u32 *)cfg_base));
+
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ))
+ return 1;
+
+ return 0;
+}
+
+int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data = 0;
+
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if (size == 4) {
+ data = val;
+ } else {
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus,
+ devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
new file mode 100644
index 0000000..603d749
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.c
@@ -0,0 +1,297 @@
+/*
+ * 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/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+
+#include <asm/pci.h>
+#include <asm/gpio.h>
+#include <asm/addrspace.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BASE 0x17000000
+#define LTQ_PCI_CFG_SIZE 0x00008000
+#define LTQ_PCI_MEM_BASE 0x18000000
+#define LTQ_PCI_MEM_SIZE 0x02000000
+#define LTQ_PCI_IO_BASE 0x1AE00000
+#define LTQ_PCI_IO_SIZE 0x00200000
+
+#define PCI_CR_FCI_ADDR_MAP0 0x00C0
+#define PCI_CR_FCI_ADDR_MAP1 0x00C4
+#define PCI_CR_FCI_ADDR_MAP2 0x00C8
+#define PCI_CR_FCI_ADDR_MAP3 0x00CC
+#define PCI_CR_FCI_ADDR_MAP4 0x00D0
+#define PCI_CR_FCI_ADDR_MAP5 0x00D4
+#define PCI_CR_FCI_ADDR_MAP6 0x00D8
+#define PCI_CR_FCI_ADDR_MAP7 0x00DC
+#define PCI_CR_CLK_CTRL 0x0000
+#define PCI_CR_PCI_MOD 0x0030
+#define PCI_CR_PC_ARB 0x0080
+#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4
+#define PCI_CR_BAR11MASK 0x0044
+#define PCI_CR_BAR12MASK 0x0048
+#define PCI_CR_BAR13MASK 0x004C
+#define PCI_CS_BASE_ADDR1 0x0010
+#define PCI_CR_PCI_ADDR_MAP11 0x0064
+#define PCI_CR_FCI_BURST_LENGTH 0x00E8
+#define PCI_CR_PCI_EOI 0x002C
+#define PCI_CS_STS_CMD 0x0004
+
+#define PCI_MASTER0_REQ_MASK_2BITS 8
+#define PCI_MASTER1_REQ_MASK_2BITS 10
+#define PCI_MASTER2_REQ_MASK_2BITS 12
+#define INTERNAL_ARB_ENABLE_BIT 0
+
+#define LTQ_CGU_IFCCR 0x0018
+#define LTQ_CGU_PCICR 0x0034
+
+#define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y))
+#define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x))
+
+#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y))
+#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x))
+
+struct ltq_pci_gpio_map {
+ int pin;
+ int alt0;
+ int alt1;
+ int dir;
+ char *name;
+};
+
+/* the pci core can make use of the following gpios */
+static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = {
+ { 0, 1, 0, 0, "pci-exin0" },
+ { 1, 1, 0, 0, "pci-exin1" },
+ { 2, 1, 0, 0, "pci-exin2" },
+ { 39, 1, 0, 0, "pci-exin3" },
+ { 10, 1, 0, 0, "pci-exin4" },
+ { 9, 1, 0, 0, "pci-exin5" },
+ { 30, 1, 0, 1, "pci-gnt1" },
+ { 23, 1, 0, 1, "pci-gnt2" },
+ { 19, 1, 0, 1, "pci-gnt3" },
+ { 38, 1, 0, 1, "pci-gnt4" },
+ { 29, 1, 0, 0, "pci-req1" },
+ { 31, 1, 0, 0, "pci-req2" },
+ { 3, 1, 0, 0, "pci-req3" },
+ { 37, 1, 0, 0, "pci-req4" },
+};
+
+__iomem void *ltq_pci_mapped_cfg;
+static __iomem void *ltq_pci_membase;
+
+int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
+
+/* Since the PCI REQ pins can be reused for other functionality, make it
+ possible to exclude those from interpretation by the PCI controller */
+static int ltq_pci_req_mask = 0xf;
+
+static int *ltq_pci_irq_map;
+
+struct pci_ops ltq_pci_ops = {
+ .read = ltq_pci_read_config_dword,
+ .write = ltq_pci_write_config_dword
+};
+
+static struct resource pci_io_resource = {
+ .name = "pci io space",
+ .start = LTQ_PCI_IO_BASE,
+ .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+ .name = "pci memory space",
+ .start = LTQ_PCI_MEM_BASE,
+ .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_controller ltq_pci_controller = {
+ .pci_ops = &ltq_pci_ops,
+ .mem_resource = &pci_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_resource = &pci_io_resource,
+ .io_offset = 0x00000000UL,
+};
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ if (ltqpci_plat_dev_init)
+ return ltqpci_plat_dev_init(dev);
+
+ return 0;
+}
+
+static u32 ltq_calc_bar11mask(void)
+{
+ u32 mem, bar11mask;
+
+ /* BAR11MASK value depends on available memory on system. */
+ mem = num_physpages * PAGE_SIZE;
+ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
+
+ return bar11mask;
+}
+
+static void ltq_pci_setup_gpio(int gpio)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) {
+ if (gpio & (1 << i)) {
+ ltq_gpio_request(ltq_pci_gpio_map[i].pin,
+ ltq_pci_gpio_map[i].alt0,
+ ltq_pci_gpio_map[i].alt1,
+ ltq_pci_gpio_map[i].dir,
+ ltq_pci_gpio_map[i].name);
+ }
+ }
+ ltq_gpio_request(21, 0, 0, 1, "pci-reset");
+ ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK;
+}
+
+static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
+{
+ u32 temp_buffer;
+
+ /* set clock to 33Mhz */
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+
+ /* external or internal clock ? */
+ if (conf->clock) {
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16),
+ LTQ_CGU_IFCCR);
+ ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR);
+ } else {
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16),
+ LTQ_CGU_IFCCR);
+ ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
+ }
+
+ /* setup pci clock and gpis used by pci */
+ ltq_pci_setup_gpio(conf->gpio);
+
+ /* enable auto-switching between PCI and EBU */
+ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
+
+ /* busy, i.e. configuration is not done, PCI access has to be retried */
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+ /* BUS Master/IO/MEM access */
+ ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD);
+
+ /* enable external 2 PCI masters */
+ temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB);
+ temp_buffer &= (~(ltq_pci_req_mask << 16));
+ /* enable internal arbiter */
+ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
+ /* enable internal PCI master reqest */
+ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
+
+ /* enable EBU request */
+ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS));
+
+ /* enable all external masters request */
+ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS));
+ ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB);
+ wmb();
+
+ /* setup BAR memory regions */
+ ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0);
+ ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1);
+ ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2);
+ ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3);
+ ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4);
+ ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5);
+ ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6);
+ ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7);
+ ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg);
+ ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK);
+ ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11);
+ ltq_pci_w32(0, PCI_CS_BASE_ADDR1);
+ /* both TX and RX endian swap are enabled */
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI);
+ wmb();
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000,
+ PCI_CR_BAR12MASK);
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000,
+ PCI_CR_BAR13MASK);
+ /*use 8 dw burst length */
+ ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH);
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+
+ /* setup irq line */
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON);
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
+
+ /* toggle reset pin */
+ __gpio_set_value(21, 0);
+ wmb();
+ mdelay(1);
+ __gpio_set_value(21, 1);
+ return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (ltq_pci_irq_map[slot])
+ return ltq_pci_irq_map[slot];
+ printk(KERN_ERR "ltq_pci: trying to map irq for unknown slot %d\n",
+ slot);
+
+ return 0;
+}
+
+static int __devinit ltq_pci_probe(struct platform_device *pdev)
+{
+ struct ltq_pci_data *ltq_pci_data =
+ (struct ltq_pci_data *) pdev->dev.platform_data;
+ pci_probe_only = 0;
+ ltq_pci_irq_map = ltq_pci_data->irq;
+ ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
+ ltq_pci_mapped_cfg =
+ ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
+ ltq_pci_controller.io_map_base =
+ (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
+ ltq_pci_startup(ltq_pci_data);
+ register_pci_controller(&ltq_pci_controller);
+
+ return 0;
+}
+
+static struct platform_driver
+ltq_pci_driver = {
+ .probe = ltq_pci_probe,
+ .driver = {
+ .name = "ltq_pci",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init pcibios_init(void)
+{
+ int ret = platform_driver_register(&ltq_pci_driver);
+ if (ret)
+ printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
+ return ret;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h
new file mode 100644
index 0000000..66bf6cd
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.h
@@ -0,0 +1,18 @@
+/*
+ * 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>
+ */
+
+#ifndef _LTQ_PCI_H__
+#define _LTQ_PCI_H__
+
+extern __iomem void *ltq_pci_mapped_cfg;
+extern int ltq_pci_read_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val);
+extern int ltq_pci_write_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val);
+
+#endif
--
1.7.2.3

View file

@ -0,0 +1,301 @@
From cd0d53b24ca744295d2cdf69bb2b659571091b75 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 12 Apr 2011 18:10:01 +0200
Subject: [PATCH 04/13] MIPS: Lantiq: Add NOR flash support
This patch adds the driver/map for NOR devices attached to the SoC via the
External Bus Unit (EBU).
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
Cc: linux-mips@linux-mips.org
Cc: linux-mtd@lists.infradead.org
Acked-by: Artem Bityutskiy <dedekind1@gmail.com>
Patchwork: https://patchwork.linux-mips.org/patch/2285/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
drivers/mtd/maps/Kconfig | 7 +
drivers/mtd/maps/Makefile | 1 +
drivers/mtd/maps/lantiq-flash.c | 251 +++++++++++++++++++++++++++++++++++++++
3 files changed, 259 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/maps/lantiq-flash.c
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -259,6 +259,13 @@
help
Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
+config MTD_LANTIQ
+ tristate "Lantiq SoC NOR support"
+ depends on LANTIQ
+ select MTD_PARTITIONS
+ help
+ Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
+
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -61,3 +61,4 @@
obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
+obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
--- /dev/null
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -0,0 +1,251 @@
+/*
+ * 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) 2004 Liu Peng Infineon IFAP DC COM CPE
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+/*
+ * The NOR flash is connected to the same external bus unit (EBU) as PCI.
+ * To make PCI work we need to enable the endianness swapping for the address
+ * written to the EBU. This endianness swapping works for PCI correctly but
+ * fails for attached NOR devices. To workaround this we need to use a complex
+ * map. The workaround involves swapping all addresses whilst probing the chip.
+ * Once probing is complete we stop swapping the addresses but swizzle the
+ * unlock addresses to ensure that access to the NOR device works correctly.
+ */
+
+enum {
+ LTQ_NOR_PROBING,
+ LTQ_NOR_NORMAL
+};
+
+struct ltq_mtd {
+ struct resource *res;
+ struct mtd_info *mtd;
+ struct map_info *map;
+};
+
+static char ltq_map_name[] = "ltq_nor";
+
+static map_word
+ltq_read16(struct map_info *map, unsigned long adr)
+{
+ unsigned long flags;
+ map_word temp;
+
+ if (map->map_priv_1 == LTQ_NOR_PROBING)
+ adr ^= 2;
+ spin_lock_irqsave(&ebu_lock, flags);
+ temp.x[0] = *(u16 *)(map->virt + adr);
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ return temp;
+}
+
+static void
+ltq_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+ unsigned long flags;
+
+ if (map->map_priv_1 == LTQ_NOR_PROBING)
+ adr ^= 2;
+ spin_lock_irqsave(&ebu_lock, flags);
+ *(u16 *)(map->virt + adr) = d.x[0];
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+/*
+ * The following 2 functions copy data between iomem and a cached memory
+ * section. As memcpy() makes use of pre-fetching we cannot use it here.
+ * The normal alternative of using memcpy_{to,from}io also makes use of
+ * memcpy() on MIPS so it is not applicable either. We are therefore stuck
+ * with having to use our own loop.
+ */
+static void
+ltq_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ unsigned char *f = (unsigned char *)map->virt + from;
+ unsigned char *t = (unsigned char *)to;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ while (len--)
+ *t++ = *f++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void
+ltq_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ unsigned char *f = (unsigned char *)from;
+ unsigned char *t = (unsigned char *)map->virt + to;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ while (len--)
+ *t++ = *f++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static const char const *part_probe_types[] = { "cmdlinepart", NULL };
+
+static int __init
+ltq_mtd_probe(struct platform_device *pdev)
+{
+ struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev);
+ struct ltq_mtd *ltq_mtd;
+ struct mtd_partition *parts;
+ struct resource *res;
+ int nr_parts = 0;
+ struct cfi_private *cfi;
+ int err;
+
+ ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL);
+ platform_set_drvdata(pdev, ltq_mtd);
+
+ ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ltq_mtd->res) {
+ dev_err(&pdev->dev, "failed to get memory resource");
+ err = -ENOENT;
+ goto err_out;
+ }
+
+ res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start,
+ resource_size(ltq_mtd->res), dev_name(&pdev->dev));
+ if (!ltq_mtd->res) {
+ dev_err(&pdev->dev, "failed to request mem resource");
+ err = -EBUSY;
+ goto err_out;
+ }
+
+ ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
+ ltq_mtd->map->phys = res->start;
+ ltq_mtd->map->size = resource_size(res);
+ ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev,
+ ltq_mtd->map->phys, ltq_mtd->map->size);
+ if (!ltq_mtd->map->virt) {
+ dev_err(&pdev->dev, "failed to ioremap!\n");
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ ltq_mtd->map->name = ltq_map_name;
+ ltq_mtd->map->bankwidth = 2;
+ ltq_mtd->map->read = ltq_read16;
+ ltq_mtd->map->write = ltq_write16;
+ ltq_mtd->map->copy_from = ltq_copy_from;
+ ltq_mtd->map->copy_to = ltq_copy_to;
+
+ ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING;
+ ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map);
+ ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL;
+
+ if (!ltq_mtd->mtd) {
+ dev_err(&pdev->dev, "probing failed\n");
+ err = -ENXIO;
+ goto err_unmap;
+ }
+
+ ltq_mtd->mtd->owner = THIS_MODULE;
+
+ cfi = ltq_mtd->map->fldrv_priv;
+ cfi->addr_unlock1 ^= 1;
+ cfi->addr_unlock2 ^= 1;
+
+ nr_parts = parse_mtd_partitions(ltq_mtd->mtd,
+ part_probe_types, &parts, 0);
+ if (nr_parts > 0) {
+ dev_info(&pdev->dev,
+ "using %d partitions from cmdline", nr_parts);
+ } else {
+ nr_parts = ltq_mtd_data->nr_parts;
+ parts = ltq_mtd_data->parts;
+ }
+
+ err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts);
+ if (err) {
+ dev_err(&pdev->dev, "failed to add partitions\n");
+ goto err_destroy;
+ }
+
+ return 0;
+
+err_destroy:
+ map_destroy(ltq_mtd->mtd);
+err_unmap:
+ iounmap(ltq_mtd->map->virt);
+err_free:
+ kfree(ltq_mtd->map);
+err_out:
+ kfree(ltq_mtd);
+ return err;
+}
+
+static int __devexit
+ltq_mtd_remove(struct platform_device *pdev)
+{
+ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
+
+ if (ltq_mtd) {
+ if (ltq_mtd->mtd) {
+ del_mtd_partitions(ltq_mtd->mtd);
+ map_destroy(ltq_mtd->mtd);
+ }
+ if (ltq_mtd->map->virt)
+ iounmap(ltq_mtd->map->virt);
+ kfree(ltq_mtd->map);
+ kfree(ltq_mtd);
+ }
+ return 0;
+}
+
+static struct platform_driver ltq_mtd_driver = {
+ .remove = __devexit_p(ltq_mtd_remove),
+ .driver = {
+ .name = "ltq_nor",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init
+init_ltq_mtd(void)
+{
+ int ret = platform_driver_probe(&ltq_mtd_driver, ltq_mtd_probe);
+
+ if (ret)
+ pr_err("ltq_nor: error registering platform driver");
+ return ret;
+}
+
+static void __exit
+exit_ltq_mtd(void)
+{
+ platform_driver_unregister(&ltq_mtd_driver);
+}
+
+module_init(init_ltq_mtd);
+module_exit(exit_ltq_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC NOR");

View file

@ -0,0 +1,338 @@
From 09e57348261c1ae0ff89c68679126fc76a28b2a2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2011 09:27:53 +0200
Subject: [PATCH 05/13] MIPS: Lantiq: Add platform device support
This patch adds the wrappers for registering our platform devices.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2254/
Patchwork: https://patchwork.linux-mips.org/patch/2360/
Patchwork: https://patchwork.linux-mips.org/patch/2359/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/lantiq/Makefile | 2 +-
arch/mips/lantiq/devices.c | 122 +++++++++++++++++++++++++++++++++++++++
arch/mips/lantiq/devices.h | 23 +++++++
arch/mips/lantiq/xway/Makefile | 2 +-
arch/mips/lantiq/xway/devices.c | 98 +++++++++++++++++++++++++++++++
arch/mips/lantiq/xway/devices.h | 18 ++++++
6 files changed, 263 insertions(+), 2 deletions(-)
create mode 100644 arch/mips/lantiq/devices.c
create mode 100644 arch/mips/lantiq/devices.h
create mode 100644 arch/mips/lantiq/xway/devices.c
create mode 100644 arch/mips/lantiq/xway/devices.h
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
index a268391..e5dae0e 100644
--- a/arch/mips/lantiq/Makefile
+++ b/arch/mips/lantiq/Makefile
@@ -4,7 +4,7 @@
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
-obj-y := irq.o setup.o clk.o prom.o
+obj-y := irq.o setup.o clk.o prom.o devices.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
new file mode 100644
index 0000000..7b82c34
--- /dev/null
+++ b/arch/mips/lantiq/devices.c
@@ -0,0 +1,122 @@
+/*
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/string.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 "devices.h"
+
+/* nor flash */
+static struct resource ltq_nor_resource = {
+ .name = "nor",
+ .start = LTQ_FLASH_START,
+ .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_nor = {
+ .name = "ltq_nor",
+ .resource = &ltq_nor_resource,
+ .num_resources = 1,
+};
+
+void __init ltq_register_nor(struct physmap_flash_data *data)
+{
+ ltq_nor.dev.platform_data = data;
+ platform_device_register(&ltq_nor);
+}
+
+/* watchdog */
+static struct resource ltq_wdt_resource = {
+ .name = "watchdog",
+ .start = LTQ_WDT_BASE_ADDR,
+ .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+void __init ltq_register_wdt(void)
+{
+ platform_device_register_simple("ltq_wdt", 0, &ltq_wdt_resource, 1);
+}
+
+/* asc ports */
+static struct resource ltq_asc0_resources[] = {
+ {
+ .name = "asc0",
+ .start = LTQ_ASC0_BASE_ADDR,
+ .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_TIR(0)),
+ IRQ_RES(rx, LTQ_ASC_RIR(0)),
+ IRQ_RES(err, LTQ_ASC_EIR(0)),
+};
+
+static struct resource ltq_asc1_resources[] = {
+ {
+ .name = "asc1",
+ .start = LTQ_ASC1_BASE_ADDR,
+ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_TIR(1)),
+ IRQ_RES(rx, LTQ_ASC_RIR(1)),
+ IRQ_RES(err, LTQ_ASC_EIR(1)),
+};
+
+void __init ltq_register_asc(int port)
+{
+ switch (port) {
+ case 0:
+ platform_device_register_simple("ltq_asc", 0,
+ ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources));
+ break;
+ case 1:
+ platform_device_register_simple("ltq_asc", 1,
+ ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources));
+ break;
+ default:
+ break;
+ }
+}
+
+#ifdef CONFIG_PCI
+/* pci */
+static struct platform_device ltq_pci = {
+ .name = "ltq_pci",
+ .num_resources = 0,
+};
+
+void __init ltq_register_pci(struct ltq_pci_data *data)
+{
+ ltq_pci.dev.platform_data = data;
+ platform_device_register(&ltq_pci);
+}
+#else
+void __init ltq_register_pci(struct ltq_pci_data *data)
+{
+ pr_err("kernel is compiled without PCI support\n");
+}
+#endif
diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
new file mode 100644
index 0000000..2947bb1
--- /dev/null
+++ b/arch/mips/lantiq/devices.h
@@ -0,0 +1,23 @@
+/*
+ * 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>
+ */
+
+#ifndef _LTQ_DEVICES_H__
+#define _LTQ_DEVICES_H__
+
+#include <lantiq_platform.h>
+#include <linux/mtd/physmap.h>
+
+#define IRQ_RES(resname, irq) \
+ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
+
+extern void ltq_register_nor(struct physmap_flash_data *data);
+extern void ltq_register_wdt(void);
+extern void ltq_register_asc(int port);
+extern void ltq_register_pci(struct ltq_pci_data *data);
+
+#endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 9c85ff9..74ce438 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1,4 @@
-obj-y := pmu.o ebu.o reset.o gpio.o
+obj-y := pmu.o ebu.o reset.o gpio.o devices.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
new file mode 100644
index 0000000..a71b3b5
--- /dev/null
+++ b/arch/mips/lantiq/xway/devices.c
@@ -0,0 +1,98 @@
+/*
+ * 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/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>
+
+#include "devices.h"
+
+/* gpio */
+static struct resource ltq_gpio_resource[] = {
+ {
+ .name = "gpio0",
+ .start = LTQ_GPIO0_BASE_ADDR,
+ .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "gpio1",
+ .start = LTQ_GPIO1_BASE_ADDR,
+ .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "gpio2",
+ .start = LTQ_GPIO2_BASE_ADDR,
+ .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+void __init ltq_register_gpio(void)
+{
+ platform_device_register_simple("ltq_gpio", 0,
+ &ltq_gpio_resource[0], 1);
+ platform_device_register_simple("ltq_gpio", 1,
+ &ltq_gpio_resource[1], 1);
+
+ /* AR9 and VR9 have an extra gpio block */
+ if (ltq_is_ar9() || ltq_is_vr9()) {
+ platform_device_register_simple("ltq_gpio", 2,
+ &ltq_gpio_resource[2], 1);
+ }
+}
+
+/* serial to parallel conversion */
+static struct resource ltq_stp_resource = {
+ .name = "stp",
+ .start = LTQ_STP_BASE_ADDR,
+ .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+void __init ltq_register_gpio_stp(void)
+{
+ platform_device_register_simple("ltq_stp", 0, &ltq_stp_resource, 1);
+}
+
+/* asc ports - amazon se has its own serial mapping */
+static struct resource ltq_ase_asc_resources[] = {
+ {
+ .name = "asc0",
+ .start = LTQ_ASC1_BASE_ADDR,
+ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_ASE_TIR),
+ IRQ_RES(rx, LTQ_ASC_ASE_RIR),
+ IRQ_RES(err, LTQ_ASC_ASE_EIR),
+};
+
+void __init ltq_register_ase_asc(void)
+{
+ platform_device_register_simple("ltq_asc", 0,
+ ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources));
+}
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
new file mode 100644
index 0000000..51f56b5
--- /dev/null
+++ b/arch/mips/lantiq/xway/devices.h
@@ -0,0 +1,18 @@
+/*
+ * 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>
+ */
+
+#ifndef _LTQ_DEVICES_XWAY_H__
+#define _LTQ_DEVICES_XWAY_H__
+
+#include "../devices.h"
+
+extern void ltq_register_gpio(void);
+extern void ltq_register_gpio_stp(void);
+extern void ltq_register_ase_asc(void);
+
+#endif
--
1.7.2.3

View file

@ -0,0 +1,170 @@
From 52a5369d1067d4feddbfa7ff4486a77ac9a2971e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2011 09:27:54 +0200
Subject: [PATCH 06/13] MIPS: Lantiq: Add mips_machine support
This patch adds support for Gabor's mips_machine patch.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: Gabor Juhos <juhosg@openwrt.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2251/
Patchwork: https://patchwork.linux-mips.org/patch/2358/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/Kconfig | 1 +
arch/mips/lantiq/machtypes.h | 18 ++++++++++++++++++
arch/mips/lantiq/prom.h | 1 +
arch/mips/lantiq/setup.c | 25 +++++++++++++++++++++++++
arch/mips/lantiq/xway/Makefile | 4 ++--
arch/mips/lantiq/xway/setup-ase.c | 19 +++++++++++++++++++
arch/mips/lantiq/xway/setup-xway.c | 20 ++++++++++++++++++++
7 files changed, 86 insertions(+), 2 deletions(-)
create mode 100644 arch/mips/lantiq/machtypes.h
create mode 100644 arch/mips/lantiq/xway/setup-ase.c
create mode 100644 arch/mips/lantiq/xway/setup-xway.c
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -190,6 +190,7 @@
select SWAP_IO_SPACE
select BOOT_RAW
select HAVE_CLK
+ select MIPS_MACHINE
config LASAT
bool "LASAT Networks platforms"
--- /dev/null
+++ b/arch/mips/lantiq/machtypes.h
@@ -0,0 +1,18 @@
+/*
+ * 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>
+ */
+
+#ifndef _LANTIQ_MACH_H__
+#define _LANTIQ_MACH_H__
+
+#include <asm/mips_machine.h>
+
+enum lantiq_mach_type {
+ LTQ_MACH_GENERIC = 0,
+};
+
+#endif
--- a/arch/mips/lantiq/prom.h
+++ b/arch/mips/lantiq/prom.h
@@ -20,5 +20,6 @@
};
extern void ltq_soc_detect(struct ltq_soc_info *i);
+extern void ltq_soc_setup(void);
#endif
--- a/arch/mips/lantiq/setup.c
+++ b/arch/mips/lantiq/setup.c
@@ -14,6 +14,12 @@
#include <lantiq_soc.h>
+#include "machtypes.h"
+#include "devices.h"
+#include "prom.h"
+
+unsigned long physical_memsize = 0L;
+
void __init plat_mem_setup(void)
{
/* assume 16M as default incase uboot fails to pass proper ramsize */
@@ -32,10 +38,32 @@
if (!strncmp(e, "memsize=", 8)) {
e += 8;
if (strict_strtoul(e, 0, &memsize))
- pr_warn("bad memsize specified\n");
+ pr_warning("bad memsize specified\n");
}
envp++;
}
memsize *= 1024 * 1024;
add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+ physical_memsize = memsize;
+}
+
+static int __init
+lantiq_setup(void)
+{
+ ltq_soc_setup();
+ mips_machine_setup();
+ return 0;
}
+
+arch_initcall(lantiq_setup);
+
+static void __init
+lantiq_generic_init(void)
+{
+ /* Nothing to do */
+}
+
+MIPS_MACHINE(LTQ_MACH_GENERIC,
+ "Generic",
+ "Generic Lantiq based board",
+ lantiq_generic_init);
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1,4 @@
obj-y := pmu.o ebu.o reset.o gpio.o devices.o
-obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
-obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
+obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
+obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/setup-ase.c
@@ -0,0 +1,19 @@
+/*
+ * 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 <lantiq_soc.h>
+
+#include "../prom.h"
+#include "devices.h"
+
+void __init ltq_soc_setup(void)
+{
+ ltq_register_ase_asc();
+ ltq_register_gpio();
+ ltq_register_wdt();
+}
--- /dev/null
+++ b/arch/mips/lantiq/xway/setup-xway.c
@@ -0,0 +1,20 @@
+/*
+ * 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 <lantiq_soc.h>
+
+#include "../prom.h"
+#include "devices.h"
+
+void __init ltq_soc_setup(void)
+{
+ ltq_register_asc(0);
+ ltq_register_asc(1);
+ ltq_register_gpio();
+ ltq_register_wdt();
+}

View file

@ -0,0 +1,230 @@
From ab2182fc419548455d03979683eb0e92c372ed79 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2011 09:27:55 +0200
Subject: [PATCH 07/13] MIPS: Lantiq: Add machtypes for lantiq eval kits
This patch adds mach specific code for the Lantiq EASY50712/50601 evaluation
boards
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2255/
Patchwork: https://patchwork.linux-mips.org/patch/2361/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/lantiq/Kconfig | 2 +
arch/mips/lantiq/machtypes.h | 2 +
arch/mips/lantiq/xway/Kconfig | 23 +++++++++++
arch/mips/lantiq/xway/Makefile | 3 +
arch/mips/lantiq/xway/mach-easy50601.c | 57 ++++++++++++++++++++++++++
arch/mips/lantiq/xway/mach-easy50712.c | 68 ++++++++++++++++++++++++++++++++
6 files changed, 155 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/lantiq/xway/Kconfig
create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c
create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
index 2780461..3fccf21 100644
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -18,4 +18,6 @@ config SOC_XWAY
select HW_HAS_PCI
endchoice
+source "arch/mips/lantiq/xway/Kconfig"
+
endif
diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
index ffcacfc..7e01b8c 100644
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -13,6 +13,8 @@
enum lantiq_mach_type {
LTQ_MACH_GENERIC = 0,
+ LTQ_MACH_EASY50712, /* Danube evaluation board */
+ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
};
#endif
diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig
new file mode 100644
index 0000000..2b857de
--- /dev/null
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -0,0 +1,23 @@
+if SOC_XWAY
+
+menu "MIPS Machine"
+
+config LANTIQ_MACH_EASY50712
+ bool "Easy50712 - Danube"
+ default y
+
+endmenu
+
+endif
+
+if SOC_AMAZON_SE
+
+menu "MIPS Machine"
+
+config LANTIQ_MACH_EASY50601
+ bool "Easy50601 - Amazon SE"
+ default y
+
+endmenu
+
+endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 8c06a97..b1d3640 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -2,3 +2,6 @@ obj-y := pmu.o ebu.o reset.o gpio.o devices.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
+
+obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
+obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c
new file mode 100644
index 0000000..d5aaf63
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-easy50601.c
@@ -0,0 +1,57 @@
+/*
+ * 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 = 0xE0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+
+static struct physmap_flash_data easy50601_flash_data = {
+ .nr_parts = ARRAY_SIZE(easy50601_partitions),
+ .parts = easy50601_partitions,
+};
+
+static void __init easy50601_init(void)
+{
+ ltq_register_nor(&easy50601_flash_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50601,
+ "EASY50601",
+ "EASY50601 Eval Board",
+ easy50601_init);
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
new file mode 100644
index 0000000..e5e7e09
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
@@ -0,0 +1,68 @@
+/*
+ * 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_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 = 0xe0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+
+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 void __init easy50712_init(void)
+{
+ ltq_register_gpio_stp();
+ ltq_register_nor(&easy50712_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50712,
+ "EASY50712",
+ "EASY50712 Eval Board",
+ easy50712_init);
--
1.7.2.3

View file

@ -0,0 +1,330 @@
From f9391211e47cdcc31f341d710efef4b3b46c333d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2011 09:27:56 +0200
Subject: [PATCH 08/13] MIPS: Lantiq: Add more gpio drivers
The XWAY family allows to extend the number of gpios by using shift registers or latches. This patch adds the 2 drivers needed for this. The extended gpios are output only.
[ralf@linux-mips.org: Fixed ltq_stp_probe section() attributes.]
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2258/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/lantiq/xway/Makefile | 2 +-
arch/mips/lantiq/xway/gpio_ebu.c | 126 ++++++++++++++++++++++++++++++
arch/mips/lantiq/xway/gpio_stp.c | 157 ++++++++++++++++++++++++++++++++++++++
3 files changed, 284 insertions(+), 1 deletions(-)
create mode 100644 arch/mips/lantiq/xway/gpio_ebu.c
create mode 100644 arch/mips/lantiq/xway/gpio_stp.c
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index b1d3640..6b5e07e 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1,4 @@
-obj-y := pmu.o ebu.o reset.o gpio.o devices.o
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
new file mode 100644
index 0000000..a479355
--- /dev/null
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
@@ -0,0 +1,126 @@
+/*
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <lantiq_soc.h>
+
+/*
+ * By attaching hardware latches to the EBU it is possible to create output
+ * only gpios. This driver configures a special memory address, which when
+ * written to outputs 16 bit to the latches.
+ */
+
+#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */
+#define LTQ_EBU_WP 0x80000000 /* write protect bit */
+
+/* we keep a shadow value of the last value written to the ebu */
+static int ltq_ebu_gpio_shadow = 0x0;
+static void __iomem *ltq_ebu_gpio_membase;
+
+static void ltq_ebu_apply(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1);
+ *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow;
+ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (value)
+ ltq_ebu_gpio_shadow |= (1 << offset);
+ else
+ ltq_ebu_gpio_shadow &= ~(1 << offset);
+ ltq_ebu_apply();
+}
+
+static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ ltq_ebu_set(chip, offset, value);
+
+ return 0;
+}
+
+static struct gpio_chip ltq_ebu_chip = {
+ .label = "ltq_ebu",
+ .direction_output = ltq_ebu_direction_output,
+ .set = ltq_ebu_set,
+ .base = 72,
+ .ngpio = 16,
+ .can_sleep = 1,
+ .owner = THIS_MODULE,
+};
+
+static int ltq_ebu_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ return -ENOENT;
+ }
+
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request memory resource\n");
+ return -EBUSY;
+ }
+
+ ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ltq_ebu_gpio_membase) {
+ dev_err(&pdev->dev, "Failed to ioremap mem region\n");
+ return -ENOMEM;
+ }
+
+ /* grab the default shadow value passed form the platform code */
+ ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data;
+
+ /* tell the ebu controller which memory address we will be using */
+ ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1);
+
+ /* write protect the region */
+ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
+
+ ret = gpiochip_add(&ltq_ebu_chip);
+ if (!ret)
+ ltq_ebu_apply();
+ return ret;
+}
+
+static struct platform_driver ltq_ebu_driver = {
+ .probe = ltq_ebu_probe,
+ .driver = {
+ .name = "ltq_ebu",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ltq_ebu_init(void)
+{
+ int ret = platform_driver_register(&ltq_ebu_driver);
+
+ if (ret)
+ pr_info("ltq_ebu : Error registering platfom driver!");
+ return ret;
+}
+
+postcore_initcall(ltq_ebu_init);
diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
new file mode 100644
index 0000000..67d59d6
--- /dev/null
+++ b/arch/mips/lantiq/xway/gpio_stp.c
@@ -0,0 +1,157 @@
+/*
+ * 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) 2007 John Crispin <blogic@openwrt.org>
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_STP_CON0 0x00
+#define LTQ_STP_CON1 0x04
+#define LTQ_STP_CPU0 0x08
+#define LTQ_STP_CPU1 0x0C
+#define LTQ_STP_AR 0x10
+
+#define LTQ_STP_CON_SWU (1 << 31)
+#define LTQ_STP_2HZ 0
+#define LTQ_STP_4HZ (1 << 23)
+#define LTQ_STP_8HZ (2 << 23)
+#define LTQ_STP_10HZ (3 << 23)
+#define LTQ_STP_SPEED_MASK (0xf << 23)
+#define LTQ_STP_UPD_FPI (1 << 31)
+#define LTQ_STP_UPD_MASK (3 << 30)
+#define LTQ_STP_ADSL_SRC (3 << 24)
+
+#define LTQ_STP_GROUP0 (1 << 0)
+
+#define LTQ_STP_RISING 0
+#define LTQ_STP_FALLING (1 << 26)
+#define LTQ_STP_EDGE_MASK (1 << 26)
+
+#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg)
+#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg)
+#define ltq_stp_w32_mask(clear, set, reg) \
+ ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \
+ ltq_stp_membase + (reg))
+
+static int ltq_stp_shadow = 0xffff;
+static void __iomem *ltq_stp_membase;
+
+static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (value)
+ ltq_stp_shadow |= (1 << offset);
+ else
+ ltq_stp_shadow &= ~(1 << offset);
+ ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0);
+}
+
+static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ ltq_stp_set(chip, offset, value);
+
+ return 0;
+}
+
+static struct gpio_chip ltq_stp_chip = {
+ .label = "ltq_stp",
+ .direction_output = ltq_stp_direction_output,
+ .set = ltq_stp_set,
+ .base = 48,
+ .ngpio = 24,
+ .can_sleep = 1,
+ .owner = THIS_MODULE,
+};
+
+static int ltq_stp_hw_init(void)
+{
+ /* the 3 pins used to control the external stp */
+ ltq_gpio_request(4, 1, 0, 1, "stp-st");
+ ltq_gpio_request(5, 1, 0, 1, "stp-d");
+ ltq_gpio_request(6, 1, 0, 1, "stp-sh");
+
+ /* sane defaults */
+ ltq_stp_w32(0, LTQ_STP_AR);
+ ltq_stp_w32(0, LTQ_STP_CPU0);
+ ltq_stp_w32(0, LTQ_STP_CPU1);
+ ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0);
+ ltq_stp_w32(0, LTQ_STP_CON1);
+
+ /* rising or falling edge */
+ ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0);
+
+ /* per default stp 15-0 are set */
+ ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1);
+
+ /* stp are update periodically by the FPI bus */
+ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1);
+
+ /* set stp update speed */
+ ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1);
+
+ /* tell the hardware that pin (led) 0 and 1 are controlled
+ * by the dsl arc
+ */
+ ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0);
+
+ ltq_pmu_enable(PMU_LED);
+ return 0;
+}
+
+static int __devinit ltq_stp_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int ret = 0;
+
+ if (!res)
+ return -ENOENT;
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request STP memory\n");
+ return -EBUSY;
+ }
+ ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ltq_stp_membase) {
+ dev_err(&pdev->dev, "failed to remap STP memory\n");
+ return -ENOMEM;
+ }
+ ret = gpiochip_add(&ltq_stp_chip);
+ if (!ret)
+ ret = ltq_stp_hw_init();
+
+ return ret;
+}
+
+static struct platform_driver ltq_stp_driver = {
+ .probe = ltq_stp_probe,
+ .driver = {
+ .name = "ltq_stp",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init ltq_stp_init(void)
+{
+ int ret = platform_driver_register(&ltq_stp_driver);
+
+ if (ret)
+ pr_info("ltq_stp: error registering platfom driver");
+ return ret;
+}
+
+postcore_initcall(ltq_stp_init);
--
1.7.2.3

View file

@ -1,30 +1,27 @@
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1454,6 +1454,14 @@
help
Support for Console on the NWP serial ports.
From 1d2b44b1afa3ef081cd817dbf947d48eb8f5d21a Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Apr 2011 14:10:57 +0200
Subject: [PATCH 09/13] SERIAL: Lantiq: Add driver for MIPS Lantiq SOCs.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Cc: alan@lxorguk.ukuu.org.uk
Cc: linux-mips@linux-mips.org
Cc: linux-serial@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/2269/
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
drivers/tty/serial/Kconfig | 8 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/lantiq.c | 756 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 765 insertions(+), 0 deletions(-)
create mode 100644 drivers/tty/serial/lantiq.c
+config SERIAL_LANTIQ
+ bool "Lantiq serial driver"
+ depends on LANTIQ
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ help
+ Driver for the Lantiq SoC ASC hardware
+
config SERIAL_QE
tristate "Freescale QUICC Engine serial port support"
depends on QUICC_ENGINE
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -89,3 +89,4 @@
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
--- /dev/null
+++ b/drivers/serial/lantiq.c
@@ -0,0 +1,772 @@
@@ -0,0 +1,756 @@
+/*
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
@ -44,7 +41,7 @@
+ * Copyright (C) 2004 Infineon IFAP DC COM CPE
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland
+ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
+ */
+
+#include <linux/slab.h>
@ -62,39 +59,31 @@
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#define lq_r32(reg) __raw_readl(reg)
+#define lq_r8(reg) __raw_readb(reg)
+#define lq_w32(val, reg) __raw_writel(val, reg)
+#define lq_w8(val, reg) __raw_writeb(val, reg)
+#define lq_w32_mask(clear, set, reg) lq_w32((lq_r32(reg) & ~(clear)) | (set), reg)
+#include <lantiq_soc.h>
+
+#define PORT_IFXMIPSASC 111
+#define PORT_LTQ_ASC 111
+#define MAXPORTS 2
+
+#define UART_DUMMY_UER_RX 1
+
+#define DRVNAME "lq_asc"
+
+#define DRVNAME "ltq_asc"
+#ifdef __BIG_ENDIAN
+#define IFXMIPS_ASC_TBUF (0x0020 + 3)
+#define IFXMIPS_ASC_RBUF (0x0024 + 3)
+#define LTQ_ASC_TBUF (0x0020 + 3)
+#define LTQ_ASC_RBUF (0x0024 + 3)
+#else
+#define IFXMIPS_ASC_TBUF 0x0020
+#define IFXMIPS_ASC_RBUF 0x0024
+#define LTQ_ASC_TBUF 0x0020
+#define LTQ_ASC_RBUF 0x0024
+#endif
+
+#define IFXMIPS_ASC_FSTAT 0x0048
+#define IFXMIPS_ASC_WHBSTATE 0x0018
+#define IFXMIPS_ASC_STATE 0x0014
+#define IFXMIPS_ASC_IRNCR 0x00F8
+#define IFXMIPS_ASC_CLC 0x0000
+#define IFXMIPS_ASC_ID 0x0008
+#define IFXMIPS_ASC_PISEL 0x0004
+#define IFXMIPS_ASC_TXFCON 0x0044
+#define IFXMIPS_ASC_RXFCON 0x0040
+#define IFXMIPS_ASC_CON 0x0010
+#define IFXMIPS_ASC_BG 0x0050
+#define IFXMIPS_ASC_IRNREN 0x00F4
+#define LTQ_ASC_FSTAT 0x0048
+#define LTQ_ASC_WHBSTATE 0x0018
+#define LTQ_ASC_STATE 0x0014
+#define LTQ_ASC_IRNCR 0x00F8
+#define LTQ_ASC_CLC 0x0000
+#define LTQ_ASC_ID 0x0008
+#define LTQ_ASC_PISEL 0x0004
+#define LTQ_ASC_TXFCON 0x0044
+#define LTQ_ASC_RXFCON 0x0040
+#define LTQ_ASC_CON 0x0010
+#define LTQ_ASC_BG 0x0050
+#define LTQ_ASC_IRNREN 0x00F4
+
+#define ASC_IRNREN_TX 0x1
+#define ASC_IRNREN_RX 0x2
@ -105,12 +94,6 @@
+#define ASC_IRNCR_EIR 0x4
+
+#define ASCOPT_CSIZE 0x3
+#define ASCOPT_CS7 0x1
+#define ASCOPT_CS8 0x2
+#define ASCOPT_PARENB 0x4
+#define ASCOPT_STOPB 0x8
+#define ASCOPT_PARODD 0x0
+#define ASCOPT_CREAD 0x20
+#define TXFIFO_FL 1
+#define RXFIFO_FL 1
+#define ASCCLC_DISS 0x2
@ -145,18 +128,15 @@
+#define ASCRXFCON_RXFITLOFF 8
+#define ASCFSTAT_RXFFLMASK 0x003F
+#define ASCFSTAT_TXFFLMASK 0x3F00
+#define ASCFSTAT_TXFFLOFF 8
+#define ASCFSTAT_RXFREEMASK 0x003F0000
+#define ASCFSTAT_RXFREEOFF 16
+#define ASCFSTAT_TXFREEMASK 0x3F000000
+#define ASCFSTAT_TXFREEOFF 24
+
+static void lqasc_tx_chars(struct uart_port *port);
+extern void prom_printf(const char *fmt, ...);
+static struct lq_uart_port *lqasc_port[2];
+static struct ltq_uart_port *lqasc_port[MAXPORTS];
+static struct uart_driver lqasc_reg;
+static DEFINE_SPINLOCK(ltq_asc_lock);
+
+struct lq_uart_port {
+struct ltq_uart_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int tx_irq;
@ -165,9 +145,9 @@
+};
+
+static inline struct
+lq_uart_port *to_lq_uart_port(struct uart_port *port)
+ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
+{
+ return container_of(port, struct lq_uart_port, port);
+ return container_of(port, struct ltq_uart_port, port);
+}
+
+static void
@ -180,16 +160,16 @@
+lqasc_start_tx(struct uart_port *port)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ spin_lock_irqsave(&ltq_asc_lock, flags);
+ lqasc_tx_chars(port);
+ local_irq_restore(flags);
+ spin_unlock_irqrestore(&ltq_asc_lock, flags);
+ return;
+}
+
+static void
+lqasc_stop_rx(struct uart_port *port)
+{
+ lq_w32(ASCWHBSTATE_CLRREN, port->membase + IFXMIPS_ASC_WHBSTATE);
+ ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
+}
+
+static void
@ -197,17 +177,22 @@
+{
+}
+
+static void
+static int
+lqasc_rx_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = port->state->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+ unsigned int ch = 0, rsr = 0, fifocnt;
+
+ fifocnt = lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+ if (!tty) {
+ dev_dbg(port->dev, "%s:tty is busy now", __func__);
+ return -EBUSY;
+ }
+ fifocnt =
+ ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+ while (fifocnt--) {
+ u8 flag = TTY_NORMAL;
+ ch = lq_r8(port->membase + IFXMIPS_ASC_RBUF);
+ rsr = (lq_r32(port->membase + IFXMIPS_ASC_STATE)
+ ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
+ rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
+ & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
+ tty_flip_buffer_push(tty);
+ port->icount.rx++;
@ -219,17 +204,17 @@
+ if (rsr & ASCSTATE_ANY) {
+ if (rsr & ASCSTATE_PE) {
+ port->icount.parity++;
+ lq_w32_mask(0, ASCWHBSTATE_CLRPE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
+ port->membase + LTQ_ASC_WHBSTATE);
+ } else if (rsr & ASCSTATE_FE) {
+ port->icount.frame++;
+ lq_w32_mask(0, ASCWHBSTATE_CLRFE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
+ port->membase + LTQ_ASC_WHBSTATE);
+ }
+ if (rsr & ASCSTATE_ROE) {
+ port->icount.overrun++;
+ lq_w32_mask(0, ASCWHBSTATE_CLRROE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
+ port->membase + LTQ_ASC_WHBSTATE);
+ }
+
+ rsr &= port->read_status_mask;
@ -253,7 +238,8 @@
+ }
+ if (ch != 0)
+ tty_flip_buffer_push(tty);
+ return;
+ tty_kref_put(tty);
+ return 0;
+}
+
+static void
@ -265,10 +251,10 @@
+ return;
+ }
+
+ while (((lq_r32(port->membase + IFXMIPS_ASC_FSTAT) &
+ while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
+ ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
+ if (port->x_char) {
+ lq_w8(port->x_char, port->membase + IFXMIPS_ASC_TBUF);
+ ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
+ port->icount.tx++;
+ port->x_char = 0;
+ continue;
@ -277,8 +263,8 @@
+ if (uart_circ_empty(xmit))
+ break;
+
+ lq_w8(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + IFXMIPS_ASC_TBUF);
+ ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + LTQ_ASC_TBUF);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
@ -290,8 +276,11 @@
+static irqreturn_t
+lqasc_tx_int(int irq, void *_port)
+{
+ unsigned long flags;
+ struct uart_port *port = (struct uart_port *)_port;
+ lq_w32(ASC_IRNCR_TIR, port->membase + IFXMIPS_ASC_IRNCR);
+ spin_lock_irqsave(&ltq_asc_lock, flags);
+ ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
+ spin_unlock_irqrestore(&ltq_asc_lock, flags);
+ lqasc_start_tx(port);
+ return IRQ_HANDLED;
+}
@ -299,19 +288,25 @@
+static irqreturn_t
+lqasc_err_int(int irq, void *_port)
+{
+ unsigned long flags;
+ struct uart_port *port = (struct uart_port *)_port;
+ spin_lock_irqsave(&ltq_asc_lock, flags);
+ /* clear any pending interrupts */
+ lq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE,
+ port->membase + IFXMIPS_ASC_WHBSTATE);
+ ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
+ ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
+ spin_unlock_irqrestore(&ltq_asc_lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_rx_int(int irq, void *_port)
+{
+ unsigned long flags;
+ struct uart_port *port = (struct uart_port *)_port;
+ lq_w32(ASC_IRNCR_RIR, port->membase + IFXMIPS_ASC_IRNCR);
+ spin_lock_irqsave(&ltq_asc_lock, flags);
+ ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
+ lqasc_rx_chars(port);
+ spin_unlock_irqrestore(&ltq_asc_lock, flags);
+ return IRQ_HANDLED;
+}
+
@ -319,7 +314,7 @@
+lqasc_tx_empty(struct uart_port *port)
+{
+ int status;
+ status = lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+ status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+ return status ? 0 : TIOCSER_TEMT;
+}
+
@ -342,73 +337,75 @@
+static int
+lqasc_startup(struct uart_port *port)
+{
+ struct lq_uart_port *ifx_port = to_lq_uart_port(port);
+ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+ int retval;
+
+ port->uartclk = clk_get_rate(ifx_port->clk);
+ port->uartclk = clk_get_rate(ltq_port->clk);
+
+ lq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
+ port->membase + IFXMIPS_ASC_CLC);
+ ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
+ port->membase + LTQ_ASC_CLC);
+
+ lq_w32(0, port->membase + IFXMIPS_ASC_PISEL);
+ lq_w32(
+ ltq_w32(0, port->membase + LTQ_ASC_PISEL);
+ ltq_w32(
+ ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
+ ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
+ port->membase + IFXMIPS_ASC_TXFCON);
+ lq_w32(
+ port->membase + LTQ_ASC_TXFCON);
+ ltq_w32(
+ ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
+ | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
+ port->membase + IFXMIPS_ASC_RXFCON);
+ /* make sure other settings are written to hardware before setting enable bits */
+ port->membase + LTQ_ASC_RXFCON);
+ /* make sure other settings are written to hardware before
+ * setting enable bits
+ */
+ wmb();
+ lq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
+ ASCCON_ROEN, port->membase + IFXMIPS_ASC_CON);
+ ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
+ ASCCON_ROEN, port->membase + LTQ_ASC_CON);
+
+ retval = request_irq(ifx_port->tx_irq, lqasc_tx_int,
+ retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
+ IRQF_DISABLED, "asc_tx", port);
+ if (retval) {
+ pr_err("failed to request lqasc_tx_int\n");
+ return retval;
+ }
+
+ retval = request_irq(ifx_port->rx_irq, lqasc_rx_int,
+ retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
+ IRQF_DISABLED, "asc_rx", port);
+ if (retval) {
+ pr_err("failed to request lqasc_rx_int\n");
+ goto err1;
+ }
+
+ retval = request_irq(ifx_port->err_irq, lqasc_err_int,
+ retval = request_irq(ltq_port->err_irq, lqasc_err_int,
+ IRQF_DISABLED, "asc_err", port);
+ if (retval) {
+ pr_err("failed to request lqasc_err_int\n");
+ goto err2;
+ }
+
+ lq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+ port->membase + IFXMIPS_ASC_IRNREN);
+ ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+ port->membase + LTQ_ASC_IRNREN);
+ return 0;
+
+err2:
+ free_irq(ifx_port->rx_irq, port);
+ free_irq(ltq_port->rx_irq, port);
+err1:
+ free_irq(ifx_port->tx_irq, port);
+ free_irq(ltq_port->tx_irq, port);
+ return retval;
+}
+
+static void
+lqasc_shutdown(struct uart_port *port)
+{
+ struct lq_uart_port *ifx_port = to_lq_uart_port(port);
+ free_irq(ifx_port->tx_irq, port);
+ free_irq(ifx_port->rx_irq, port);
+ free_irq(ifx_port->err_irq, port);
+ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+ free_irq(ltq_port->tx_irq, port);
+ free_irq(ltq_port->rx_irq, port);
+ free_irq(ltq_port->err_irq, port);
+
+ lq_w32(0, port->membase + IFXMIPS_ASC_CON);
+ lq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
+ port->membase + IFXMIPS_ASC_RXFCON);
+ lq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
+ port->membase + IFXMIPS_ASC_TXFCON);
+ ltq_w32(0, port->membase + LTQ_ASC_CON);
+ ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
+ port->membase + LTQ_ASC_RXFCON);
+ ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
+ port->membase + LTQ_ASC_TXFCON);
+}
+
+static void
@ -417,7 +414,7 @@
+{
+ unsigned int cflag;
+ unsigned int iflag;
+ unsigned int quot;
+ unsigned int divisor;
+ unsigned int baud;
+ unsigned int con = 0;
+ unsigned long flags;
@ -433,10 +430,14 @@
+ case CS5:
+ case CS6:
+ default:
+ new->c_cflag &= ~ CSIZE;
+ new->c_cflag |= CS8;
+ con = ASCCON_M_8ASYNC;
+ break;
+ }
+
+ cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
+
+ if (cflag & CSTOPB)
+ con |= ASCCON_STP;
+
@ -470,41 +471,45 @@
+ /* set error signals - framing, parity and overrun, enable receiver */
+ con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
+
+ local_irq_save(flags);
+ spin_lock_irqsave(&ltq_asc_lock, flags);
+
+ /* set up CON */
+ lq_w32_mask(0, con, port->membase + IFXMIPS_ASC_CON);
+ ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
+
+ /* Set baud rate - take a divider of 2 into account */
+ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud);
+ quot = quot / 2 - 1;
+ divisor = uart_get_divisor(port, baud);
+ divisor = divisor / 2 - 1;
+
+ /* disable the baudrate generator */
+ lq_w32_mask(ASCCON_R, 0, port->membase + IFXMIPS_ASC_CON);
+ ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
+
+ /* make sure the fractional divider is off */
+ lq_w32_mask(ASCCON_FDE, 0, port->membase + IFXMIPS_ASC_CON);
+ ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
+
+ /* set up to use divisor of 2 */
+ lq_w32_mask(ASCCON_BRS, 0, port->membase + IFXMIPS_ASC_CON);
+ ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
+
+ /* now we can write the new baudrate into the register */
+ lq_w32(quot, port->membase + IFXMIPS_ASC_BG);
+ ltq_w32(divisor, port->membase + LTQ_ASC_BG);
+
+ /* turn the baudrate generator back on */
+ lq_w32_mask(0, ASCCON_R, port->membase + IFXMIPS_ASC_CON);
+ ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
+
+ /* enable rx */
+ lq_w32(ASCWHBSTATE_SETREN, port->membase + IFXMIPS_ASC_WHBSTATE);
+ ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
+
+ local_irq_restore(flags);
+ spin_unlock_irqrestore(&ltq_asc_lock, flags);
+
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(new))
+ tty_termios_encode_baud_rate(new, baud, baud);
+}
+
+static const char*
+lqasc_type(struct uart_port *port)
+{
+ if (port->type == PORT_IFXMIPSASC)
+ if (port->type == PORT_LTQ_ASC)
+ return DRVNAME;
+ else
+ return NULL;
@ -523,16 +528,26 @@
+lqasc_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *mmres;
+ struct resource *res;
+ int size;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mmres)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot obtain I/O memory region");
+ return -ENODEV;
+ size = resource_size(mmres);
+ }
+ size = resource_size(res);
+
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ size, dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "cannot request I/O memory region");
+ return -EBUSY;
+ }
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap_nocache(port->mapbase, size);
+ port->membase = devm_ioremap_nocache(&pdev->dev,
+ port->mapbase, size);
+ if (port->membase == NULL)
+ return -ENOMEM;
+ }
@ -543,7 +558,7 @@
+lqasc_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_IFXMIPSASC;
+ port->type = PORT_LTQ_ASC;
+ lqasc_request_port(port);
+ }
+}
@ -553,7 +568,7 @@
+ struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC)
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
@ -590,38 +605,38 @@
+ return;
+
+ do {
+ fifofree = (lq_r32(port->membase + IFXMIPS_ASC_FSTAT)
+ fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
+ & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
+ } while (fifofree == 0);
+ lq_w8(ch, port->membase + IFXMIPS_ASC_TBUF);
+ ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
+}
+
+
+static void
+lqasc_console_write(struct console *co, const char *s, u_int count)
+{
+ struct lq_uart_port *ifx_port;
+ struct ltq_uart_port *ltq_port;
+ struct uart_port *port;
+ unsigned long flags;
+
+ if (co->index >= MAXPORTS)
+ return;
+
+ ifx_port = lqasc_port[co->index];
+ if (!ifx_port)
+ ltq_port = lqasc_port[co->index];
+ if (!ltq_port)
+ return;
+
+ port = &ifx_port->port;
+ port = &ltq_port->port;
+
+ local_irq_save(flags);
+ spin_lock_irqsave(&ltq_asc_lock, flags);
+ uart_console_write(port, s, count, lqasc_console_putchar);
+ local_irq_restore(flags);
+ spin_unlock_irqrestore(&ltq_asc_lock, flags);
+}
+
+static int __init
+lqasc_console_setup(struct console *co, char *options)
+{
+ struct lq_uart_port *ifx_port;
+ struct ltq_uart_port *ltq_port;
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
@ -631,13 +646,13 @@
+ if (co->index >= MAXPORTS)
+ return -ENODEV;
+
+ ifx_port = lqasc_port[co->index];
+ if (!ifx_port)
+ ltq_port = lqasc_port[co->index];
+ if (!ltq_port)
+ return -ENODEV;
+
+ port = &ifx_port->port;
+ port = &ltq_port->port;
+
+ port->uartclk = clk_get_rate(ifx_port->clk);
+ port->uartclk = clk_get_rate(ltq_port->clk);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
@ -645,7 +660,7 @@
+}
+
+static struct console lqasc_console = {
+ .name = "ttyS",
+ .name = "ttyLTQ",
+ .write = lqasc_console_write,
+ .device = uart_console_device,
+ .setup = lqasc_console_setup,
@ -665,17 +680,17 @@
+static struct uart_driver lqasc_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = DRVNAME,
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .dev_name = "ttyLTQ",
+ .major = 0,
+ .minor = 0,
+ .nr = MAXPORTS,
+ .cons = &lqasc_console,
+};
+
+static int __devinit
+static int __init
+lqasc_probe(struct platform_device *pdev)
+{
+ struct lq_uart_port *ifx_port;
+ struct ltq_uart_port *ltq_port;
+ struct uart_port *port;
+ struct resource *mmres, *irqres;
+ int tx_irq, rx_irq, err_irq;
@ -700,69 +715,43 @@
+ }
+
+ tx_irq = platform_get_irq_byname(pdev, "tx");
+ if (tx_irq < 0) {
+ /* without named resources: assume standard irq scheme */
+ tx_irq = irqres->start;
+ rx_irq = irqres->start+2;
+ err_irq = irqres->start+3;
+ } else {
+ /* other irqs must be named also! */
+ rx_irq = platform_get_irq_byname(pdev, "rx");
+ err_irq = platform_get_irq_byname(pdev, "err");
+ if ((rx_irq < 0) | (err_irq < 0))
+ if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0))
+ return -ENODEV;
+ }
+
+ ifx_port = kzalloc(sizeof(struct lq_uart_port), GFP_KERNEL);
+ if (!ifx_port)
+ ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL);
+ if (!ltq_port)
+ return -ENOMEM;
+
+ port = &ifx_port->port;
+ port = &ltq_port->port;
+
+ port->iotype = SERIAL_IO_MEM;
+ port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->ops = &lqasc_pops;
+ port->fifosize = 16;
+ port->type = PORT_IFXMIPSASC,
+ port->type = PORT_LTQ_ASC,
+ port->line = pdev->id;
+ port->dev = &pdev->dev;
+
+ port->irq = tx_irq; /* unused, just to be backward-compatibe */
+ port->mapbase = mmres->start;
+
+ ifx_port->clk = clk;
+ ltq_port->clk = clk;
+
+ ifx_port->tx_irq = tx_irq;
+ ifx_port->rx_irq = rx_irq;
+ ifx_port->err_irq = err_irq;
+ ltq_port->tx_irq = tx_irq;
+ ltq_port->rx_irq = rx_irq;
+ ltq_port->err_irq = err_irq;
+
+ lqasc_port[pdev->id] = ifx_port;
+ platform_set_drvdata(pdev, ifx_port);
+ lqasc_port[pdev->id] = ltq_port;
+ platform_set_drvdata(pdev, ltq_port);
+
+ ret = uart_add_one_port(&lqasc_reg, port);
+
+ return ret;
+}
+
+static int __devexit
+lqasc_remove(struct platform_device *pdev)
+{
+ struct lq_uart_port *ifx_port = platform_get_drvdata(pdev);
+ int ret;
+
+ clk_put(ifx_port->clk);
+ platform_set_drvdata(pdev, NULL);
+ lqasc_port[pdev->id] = NULL;
+ ret = uart_remove_one_port(&lqasc_reg, &ifx_port->port);
+ kfree(ifx_port);
+
+ return 0;
+}
+
+static struct platform_driver lqasc_driver = {
+ .probe = lqasc_probe,
+ .remove = __devexit_p(lqasc_remove),
+
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
@ -778,22 +767,38 @@
+ if (ret != 0)
+ return ret;
+
+ ret = platform_driver_register(&lqasc_driver);
+ ret = platform_driver_probe(&lqasc_driver, lqasc_probe);
+ if (ret != 0)
+ uart_unregister_driver(&lqasc_reg);
+
+ return ret;
+}
+
+void __exit
+exit_lqasc(void)
+{
+ platform_driver_unregister(&lqasc_driver);
+ uart_unregister_driver(&lqasc_reg);
+}
+
+module_init(init_lqasc);
+module_exit(exit_lqasc);
+
+MODULE_DESCRIPTION("Lantiq serial port driver");
+MODULE_LICENSE("GPL");
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1383,6 +1383,14 @@
help
Support for Console on the NWP serial ports.
+config SERIAL_LANTIQ
+ bool "Lantiq serial driver"
+ depends on LANTIQ
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for console and UART on Lantiq SoCs.
+
config SERIAL_QE
tristate "Freescale QUICC Engine serial port support"
depends on QUICC_ENGINE
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -81,3 +81,4 @@
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
+obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o

View file

@ -0,0 +1,387 @@
From bd620ec1ca053bab8ce2562968700e6f80e4ff83 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 6 May 2011 00:10:00 +0200
Subject: [PATCH 10/13] MIPS: Lantiq: Add DMA support
This patch adds support for the DMA engine found inside the XWAY family of
SoCs. The engine has 5 ports and 20 channels.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2355/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 +-
arch/mips/include/asm/mach-lantiq/xway/xway_dma.h | 60 +++++
arch/mips/lantiq/xway/Makefile | 2 +-
arch/mips/lantiq/xway/devices.h | 1 +
arch/mips/lantiq/xway/dma.c | 253 ++++++++++++++++++++
5 files changed, 317 insertions(+), 2 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
create mode 100644 arch/mips/lantiq/xway/dma.c
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
index 343e82c..4827afb 100644
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -86,7 +86,8 @@
#define LTQ_PPE32_SIZE 0x40000
/* DMA */
-#define LTQ_DMA_BASE_ADDR 0xBE104100
+#define LTQ_DMA_BASE_ADDR 0x1E104100
+#define LTQ_DMA_SIZE 0x800
/* PCI */
#define PCI_CR_BASE_ADDR 0x1E105400
diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
new file mode 100644
index 0000000..872943a
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef LTQ_DMA_H__
+#define LTQ_DMA_H__
+
+#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */
+#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */
+
+#define LTQ_DMA_OWN BIT(31) /* owner bit */
+#define LTQ_DMA_C BIT(30) /* complete bit */
+#define LTQ_DMA_SOP BIT(29) /* start of packet */
+#define LTQ_DMA_EOP BIT(28) /* end of packet */
+#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */
+#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */
+#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */
+
+struct ltq_dma_desc {
+ u32 ctl;
+ u32 addr;
+};
+
+struct ltq_dma_channel {
+ int nr; /* the channel number */
+ int irq; /* the mapped irq */
+ int desc; /* the current descriptor */
+ struct ltq_dma_desc *desc_base; /* the descriptor base */
+ int phys; /* physical addr */
+};
+
+enum {
+ DMA_PORT_ETOP = 0,
+ DMA_PORT_DEU,
+};
+
+extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_open(struct ltq_dma_channel *ch);
+extern void ltq_dma_close(struct ltq_dma_channel *ch);
+extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch);
+extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch);
+extern void ltq_dma_free(struct ltq_dma_channel *ch);
+extern void ltq_dma_init_port(int p);
+
+#endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 6b5e07e..c517f2e 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1,4 @@
-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
index 51f56b5..d573084 100644
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -10,6 +10,7 @@
#define _LTQ_DEVICES_XWAY_H__
#include "../devices.h"
+#include <linux/phy.h>
extern void ltq_register_gpio(void);
extern void ltq_register_gpio_stp(void);
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
new file mode 100644
index 0000000..4278a45
--- /dev/null
+++ b/arch/mips/lantiq/xway/dma.c
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include <lantiq_soc.h>
+#include <xway_dma.h>
+
+#define LTQ_DMA_CTRL 0x10
+#define LTQ_DMA_CPOLL 0x14
+#define LTQ_DMA_CS 0x18
+#define LTQ_DMA_CCTRL 0x1C
+#define LTQ_DMA_CDBA 0x20
+#define LTQ_DMA_CDLEN 0x24
+#define LTQ_DMA_CIS 0x28
+#define LTQ_DMA_CIE 0x2C
+#define LTQ_DMA_PS 0x40
+#define LTQ_DMA_PCTRL 0x44
+#define LTQ_DMA_IRNEN 0xf4
+
+#define DMA_DESCPT BIT(3) /* descriptor complete irq */
+#define DMA_TX BIT(8) /* TX channel direction */
+#define DMA_CHAN_ON BIT(0) /* channel on / off bit */
+#define DMA_PDEN BIT(6) /* enable packet drop */
+#define DMA_CHAN_RST BIT(1) /* channel on / off bit */
+#define DMA_RESET BIT(0) /* channel on / off bit */
+#define DMA_IRQ_ACK 0x7e /* IRQ status register */
+#define DMA_POLL BIT(31) /* turn on channel polling */
+#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
+#define DMA_2W_BURST BIT(1) /* 2 word burst length */
+#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
+#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */
+#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
+
+#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x))
+#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y))
+#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \
+ ltq_dma_membase + (z))
+
+static struct resource ltq_dma_resource = {
+ .name = "dma",
+ .start = LTQ_DMA_BASE_ADDR,
+ .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_dma_membase;
+
+void
+ltq_dma_enable_irq(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_enable_irq);
+
+void
+ltq_dma_disable_irq(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_disable_irq);
+
+void
+ltq_dma_ack_irq(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_ack_irq);
+
+void
+ltq_dma_open(struct ltq_dma_channel *ch)
+{
+ unsigned long flag;
+
+ local_irq_save(flag);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL);
+ ltq_dma_enable_irq(ch);
+ local_irq_restore(flag);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_open);
+
+void
+ltq_dma_close(struct ltq_dma_channel *ch)
+{
+ unsigned long flag;
+
+ local_irq_save(flag);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ ltq_dma_disable_irq(ch);
+ local_irq_restore(flag);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_close);
+
+static void
+ltq_dma_alloc(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ ch->desc = 0;
+ ch->desc_base = dma_alloc_coherent(NULL,
+ LTQ_DESC_NUM * LTQ_DESC_SIZE,
+ &ch->phys, GFP_ATOMIC);
+ memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE);
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32(ch->phys, LTQ_DMA_CDBA);
+ ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ wmb();
+ ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL);
+ while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST)
+ ;
+ local_irq_restore(flags);
+}
+
+void
+ltq_dma_alloc_tx(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ ltq_dma_alloc(ch);
+
+ local_irq_save(flags);
+ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+ ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx);
+
+void
+ltq_dma_alloc_rx(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ ltq_dma_alloc(ch);
+
+ local_irq_save(flags);
+ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+ ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx);
+
+void
+ltq_dma_free(struct ltq_dma_channel *ch)
+{
+ if (!ch->desc_base)
+ return;
+ ltq_dma_close(ch);
+ dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE,
+ ch->desc_base, ch->phys);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_free);
+
+void
+ltq_dma_init_port(int p)
+{
+ ltq_dma_w32(p, LTQ_DMA_PS);
+ switch (p) {
+ case DMA_PORT_ETOP:
+ /*
+ * Tell the DMA engine to swap the endianess of data frames and
+ * drop packets if the channel arbitration fails.
+ */
+ ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN,
+ LTQ_DMA_PCTRL);
+ break;
+
+ case DMA_PORT_DEU:
+ ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2),
+ LTQ_DMA_PCTRL);
+ break;
+
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ltq_dma_init_port);
+
+int __init
+ltq_dma_init(void)
+{
+ int i;
+
+ /* insert and request the memory region */
+ if (insert_resource(&iomem_resource, &ltq_dma_resource) < 0)
+ panic("Failed to insert dma memory\n");
+
+ if (request_mem_region(ltq_dma_resource.start,
+ resource_size(&ltq_dma_resource), "dma") < 0)
+ panic("Failed to request dma memory\n");
+
+ /* remap dma register range */
+ ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start,
+ resource_size(&ltq_dma_resource));
+ if (!ltq_dma_membase)
+ panic("Failed to remap dma memory\n");
+
+ /* power up and reset the dma engine */
+ ltq_pmu_enable(PMU_DMA);
+ ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL);
+
+ /* disable all interrupts */
+ ltq_dma_w32(0, LTQ_DMA_IRNEN);
+
+ /* reset/configure each channel */
+ for (i = 0; i < DMA_MAX_CHANNEL; i++) {
+ ltq_dma_w32(i, LTQ_DMA_CS);
+ ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
+ ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ }
+ return 0;
+}
+
+postcore_initcall(ltq_dma_init);
--
1.7.2.3

View file

@ -0,0 +1,943 @@
From 435de86088af82496bcba69165cd7422bb4622ec Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 6 May 2011 00:10:01 +0200
Subject: [PATCH 11/13] MIPS: Lantiq: Add ethernet driver
This patch adds the driver for the ETOP Packet Processing Engine (PPE32)
found inside the XWAY family of Lantiq MIPS SoCs. This driver makes 100MBit
ethernet work. Support for all 8 dma channels, gbit and the embedded switch
found on the ar9/vr9 still needs to be implemented.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
Cc: netdev@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/2357/
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
.../mips/include/asm/mach-lantiq/lantiq_platform.h | 7 +
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 +-
arch/mips/lantiq/xway/devices.c | 23 +
arch/mips/lantiq/xway/devices.h | 1 +
drivers/net/Kconfig | 7 +
drivers/net/Makefile | 1 +
drivers/net/lantiq_etop.c | 805 ++++++++++++++++++++
7 files changed, 846 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/lantiq_etop.c
--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -10,6 +10,7 @@
#define _LANTIQ_PLATFORM_H__
#include <linux/mtd/partitions.h>
+#include <linux/socket.h>
/* struct used to pass info to the pci core */
enum {
@@ -43,4 +44,10 @@
int irq[16];
};
+/* struct used to pass info to network drivers */
+struct ltq_eth_data {
+ struct sockaddr mac;
+ int mii_mode;
+};
+
#endif
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -82,8 +82,8 @@
#define PMU_SWITCH 0x10000000
/* ETOP - ethernet */
-#define LTQ_PPE32_BASE_ADDR 0xBE180000
-#define LTQ_PPE32_SIZE 0x40000
+#define LTQ_ETOP_BASE_ADDR 0x1E180000
+#define LTQ_ETOP_SIZE 0x40000
/* DMA */
#define LTQ_DMA_BASE_ADDR 0x1E104100
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -96,3 +96,26 @@
platform_device_register_simple("ltq_asc", 0,
ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources));
}
+
+/* ethernet */
+static struct resource ltq_etop_resources = {
+ .name = "etop",
+ .start = LTQ_ETOP_BASE_ADDR,
+ .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_etop = {
+ .name = "ltq_etop",
+ .resource = &ltq_etop_resources,
+ .num_resources = 1,
+};
+
+void __init
+ltq_register_etop(struct ltq_eth_data *eth)
+{
+ if (eth) {
+ ltq_etop.dev.platform_data = eth;
+ platform_device_register(&ltq_etop);
+ }
+}
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -15,5 +15,6 @@
extern void ltq_register_gpio(void);
extern void ltq_register_gpio_stp(void);
extern void ltq_register_ase_asc(void);
+extern void ltq_register_etop(struct ltq_eth_data *eth);
#endif
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1951,6 +1951,13 @@
This driver supports the ethernet MACs in the Broadcom 63xx
MIPS chipset family (BCM63XX).
+config LANTIQ_ETOP
+ tristate "Lantiq SoC ETOP driver"
+ depends on SOC_TYPE_XWAY
+ help
+ Support for the MII0 inside the Lantiq SoC
+
+
source "drivers/net/fs_enet/Kconfig"
endif # NET_ETHERNET
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -246,6 +246,7 @@
obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_ENC28J60) += enc28j60.o
obj-$(CONFIG_ETHOC) += ethoc.o
+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
--- /dev/null
+++ b/drivers/net/lantiq_etop.c
@@ -0,0 +1,814 @@
+/*
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/checksum.h>
+
+#include <lantiq_soc.h>
+#include <xway_dma.h>
+#include <lantiq_platform.h>
+
+#define LTQ_ETOP_MDIO 0x11804
+#define MDIO_REQUEST 0x80000000
+#define MDIO_READ 0x40000000
+#define MDIO_ADDR_MASK 0x1f
+#define MDIO_ADDR_OFFSET 0x15
+#define MDIO_REG_MASK 0x1f
+#define MDIO_REG_OFFSET 0x10
+#define MDIO_VAL_MASK 0xffff
+
+#define PPE32_CGEN 0x800
+#define LTQ_PPE32_ENET_MAC_CFG 0x1840
+
+#define LTQ_ETOP_ENETS0 0x11850
+#define LTQ_ETOP_MAC_DA0 0x1186C
+#define LTQ_ETOP_MAC_DA1 0x11870
+#define LTQ_ETOP_CFG 0x16020
+#define LTQ_ETOP_IGPLEN 0x16080
+
+#define MAX_DMA_CHAN 0x8
+#define MAX_DMA_CRC_LEN 0x4
+#define MAX_DMA_DATA_LEN 0x600
+
+#define ETOP_FTCU BIT(28)
+#define ETOP_MII_MASK 0xf
+#define ETOP_MII_NORMAL 0xd
+#define ETOP_MII_REVERSE 0xe
+#define ETOP_PLEN_UNDER 0x40
+#define ETOP_CGEN 0x800
+
+/* use 2 static channels for TX/RX */
+#define LTQ_ETOP_TX_CHANNEL 1
+#define LTQ_ETOP_RX_CHANNEL 6
+#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL)
+#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL)
+
+#define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x))
+#define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y))
+#define ltq_etop_w32_mask(x, y, z) \
+ ltq_w32_mask(x, y, ltq_etop_membase + (z))
+
+#define DRV_VERSION "1.0"
+
+#ifndef netdev_err
+#define netdev_err(a, b, ...) printk(b, ##__VA_ARGS__)
+#endif
+
+#ifndef pr_warn
+#define pr_warn pr_warning
+#endif
+
+static void __iomem *ltq_etop_membase;
+
+struct ltq_etop_chan {
+ int idx;
+ int tx_free;
+ struct net_device *netdev;
+ struct napi_struct napi;
+ struct ltq_dma_channel dma;
+ struct sk_buff *skb[LTQ_DESC_NUM];
+};
+
+struct ltq_etop_priv {
+ struct net_device *netdev;
+ struct ltq_eth_data *pldata;
+ struct resource *res;
+
+ struct mii_bus *mii_bus;
+ struct phy_device *phydev;
+
+ struct ltq_etop_chan ch[MAX_DMA_CHAN];
+ int tx_free[MAX_DMA_CHAN >> 1];
+
+ spinlock_t lock;
+};
+
+static int
+ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
+{
+ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN);
+ if (!ch->skb[ch->dma.desc])
+ return -ENOMEM;
+ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
+ ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN,
+ DMA_FROM_DEVICE);
+ ch->dma.desc_base[ch->dma.desc].addr =
+ CPHYSADDR(ch->skb[ch->dma.desc]->data);
+ ch->dma.desc_base[ch->dma.desc].ctl =
+ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+ MAX_DMA_DATA_LEN;
+ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
+ return 0;
+}
+
+static void
+ltq_etop_hw_receive(struct ltq_etop_chan *ch)
+{
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+ struct sk_buff *skb = ch->skb[ch->dma.desc];
+ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (ltq_etop_alloc_skb(ch)) {
+ netdev_err(ch->netdev,
+ "failed to allocate new rx buffer, stopping DMA\n");
+ ltq_dma_close(&ch->dma);
+ }
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ skb_put(skb, len);
+ skb->dev = ch->netdev;
+ skb->protocol = eth_type_trans(skb, ch->netdev);
+ netif_receive_skb(skb);
+}
+
+static int
+ltq_etop_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct ltq_etop_chan *ch = container_of(napi,
+ struct ltq_etop_chan, napi);
+ int rx = 0;
+ int complete = 0;
+
+ while ((rx < budget) && !complete) {
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ ltq_etop_hw_receive(ch);
+ rx++;
+ } else {
+ complete = 1;
+ }
+ }
+ if (complete || !rx) {
+ napi_complete(&ch->napi);
+ ltq_dma_ack_irq(&ch->dma);
+ }
+ return rx;
+}
+
+static int
+ltq_etop_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct ltq_etop_chan *ch =
+ container_of(napi, struct ltq_etop_chan, napi);
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(ch->netdev, ch->idx >> 1);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ while ((ch->dma.desc_base[ch->tx_free].ctl &
+ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ dev_kfree_skb_any(ch->skb[ch->tx_free]);
+ ch->skb[ch->tx_free] = NULL;
+ memset(&ch->dma.desc_base[ch->tx_free], 0,
+ sizeof(struct ltq_dma_desc));
+ ch->tx_free++;
+ ch->tx_free %= LTQ_DESC_NUM;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (netif_tx_queue_stopped(txq))
+ netif_tx_start_queue(txq);
+ napi_complete(&ch->napi);
+ ltq_dma_ack_irq(&ch->dma);
+ return 1;
+}
+
+static irqreturn_t
+ltq_etop_dma_irq(int irq, void *_priv)
+{
+ struct ltq_etop_priv *priv = _priv;
+ int ch = irq - LTQ_DMA_CH0_INT;
+
+ napi_schedule(&priv->ch[ch].napi);
+ return IRQ_HANDLED;
+}
+
+static void
+ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ ltq_dma_free(&ch->dma);
+ if (ch->dma.irq)
+ free_irq(ch->dma.irq, priv);
+ if (IS_RX(ch->idx)) {
+ int desc;
+ for (desc = 0; desc < LTQ_DESC_NUM; desc++)
+ dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+ }
+}
+
+static void
+ltq_etop_hw_exit(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ ltq_pmu_disable(PMU_PPE);
+ for (i = 0; i < MAX_DMA_CHAN; i++)
+ if (IS_TX(i) || IS_RX(i))
+ ltq_etop_free_channel(dev, &priv->ch[i]);
+}
+
+static int
+ltq_etop_hw_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ ltq_pmu_enable(PMU_PPE);
+
+ switch (priv->pldata->mii_mode) {
+ case PHY_INTERFACE_MODE_RMII:
+ ltq_etop_w32_mask(ETOP_MII_MASK,
+ ETOP_MII_REVERSE, LTQ_ETOP_CFG);
+ break;
+
+ case PHY_INTERFACE_MODE_MII:
+ ltq_etop_w32_mask(ETOP_MII_MASK,
+ ETOP_MII_NORMAL, LTQ_ETOP_CFG);
+ break;
+
+ default:
+ netdev_err(dev, "unknown mii mode %d\n",
+ priv->pldata->mii_mode);
+ return -ENOTSUPP;
+ }
+
+ /* enable crc generation */
+ ltq_etop_w32(PPE32_CGEN, LTQ_PPE32_ENET_MAC_CFG);
+
+ ltq_dma_init_port(DMA_PORT_ETOP);
+
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ int irq = LTQ_DMA_CH0_INT + i;
+ struct ltq_etop_chan *ch = &priv->ch[i];
+
+ ch->idx = ch->dma.nr = i;
+
+ if (IS_TX(i)) {
+ ltq_dma_alloc_tx(&ch->dma);
+ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+ "etop_tx", priv);
+ } else if (IS_RX(i)) {
+ ltq_dma_alloc_rx(&ch->dma);
+ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
+ ch->dma.desc++)
+ if (ltq_etop_alloc_skb(ch))
+ return -ENOMEM;
+ ch->dma.desc = 0;
+ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+ "etop_rx", priv);
+ }
+ ch->dma.irq = irq;
+ }
+ return 0;
+}
+
+static void
+ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, "Lantiq ETOP");
+ strcpy(info->bus_info, "internal");
+ strcpy(info->version, DRV_VERSION);
+}
+
+static int
+ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int
+ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int
+ltq_etop_nway_reset(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ return phy_start_aneg(priv->phydev);
+}
+
+static const struct ethtool_ops ltq_etop_ethtool_ops = {
+ .get_drvinfo = ltq_etop_get_drvinfo,
+ .get_settings = ltq_etop_get_settings,
+ .set_settings = ltq_etop_set_settings,
+ .nway_reset = ltq_etop_nway_reset,
+};
+
+static int
+ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
+{
+ u32 val = MDIO_REQUEST |
+ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
+ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) |
+ phy_data;
+
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ;
+ ltq_etop_w32(val, LTQ_ETOP_MDIO);
+ return 0;
+}
+
+static int
+ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+ u32 val = MDIO_REQUEST | MDIO_READ |
+ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
+ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET);
+
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ;
+ ltq_etop_w32(val, LTQ_ETOP_MDIO);
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ;
+ val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK;
+ return val;
+}
+
+static void
+ltq_etop_mdio_link(struct net_device *dev)
+{
+ /* nothing to do */
+}
+
+static int
+ltq_etop_mdio_probe(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ int phy_addr;
+
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ if (priv->mii_bus->phy_map[phy_addr]) {
+ phydev = priv->mii_bus->phy_map[phy_addr];
+ break;
+ }
+ }
+
+ if (!phydev) {
+ netdev_err(dev, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
+ 0, priv->pldata->mii_mode);
+
+ if (IS_ERR(phydev)) {
+ netdev_err(dev, "Could not attach to PHY\n");
+ return PTR_ERR(phydev);
+ }
+
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+ priv->phydev = phydev;
+ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n",
+ dev->name, phydev->drv->name,
+ dev_name(&phydev->dev), phydev->irq);
+
+ return 0;
+}
+
+static int
+ltq_etop_mdio_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+ int err;
+
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus) {
+ netdev_err(dev, "failed to allocate mii bus\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ priv->mii_bus->priv = dev;
+ priv->mii_bus->read = ltq_etop_mdio_rd;
+ priv->mii_bus->write = ltq_etop_mdio_wr;
+ priv->mii_bus->name = "ltq_mii";
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!priv->mii_bus->irq) {
+ err = -ENOMEM;
+ goto err_out_free_mdiobus;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ priv->mii_bus->irq[i] = PHY_POLL;
+
+ if (mdiobus_register(priv->mii_bus)) {
+ err = -ENXIO;
+ goto err_out_free_mdio_irq;
+ }
+
+ if (ltq_etop_mdio_probe(dev)) {
+ err = -ENXIO;
+ goto err_out_unregister_bus;
+ }
+ return 0;
+
+err_out_unregister_bus:
+ mdiobus_unregister(priv->mii_bus);
+err_out_free_mdio_irq:
+ kfree(priv->mii_bus->irq);
+err_out_free_mdiobus:
+ mdiobus_free(priv->mii_bus);
+err_out:
+ return err;
+}
+
+static void
+ltq_etop_mdio_cleanup(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ phy_disconnect(priv->phydev);
+ mdiobus_unregister(priv->mii_bus);
+ kfree(priv->mii_bus->irq);
+ mdiobus_free(priv->mii_bus);
+}
+
+static int
+ltq_etop_open(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ struct ltq_etop_chan *ch = &priv->ch[i];
+
+ if (!IS_TX(i) && (!IS_RX(i)))
+ continue;
+ ltq_dma_open(&ch->dma);
+ napi_enable(&ch->napi);
+ }
+ phy_start(priv->phydev);
+ netif_tx_start_all_queues(dev);
+ return 0;
+}
+
+static int
+ltq_etop_stop(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ netif_tx_stop_all_queues(dev);
+ phy_stop(priv->phydev);
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ struct ltq_etop_chan *ch = &priv->ch[i];
+
+ if (!IS_RX(i) && !IS_TX(i))
+ continue;
+ napi_disable(&ch->napi);
+ ltq_dma_close(&ch->dma);
+ }
+ return 0;
+}
+
+static int
+ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int queue = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+ int len;
+ unsigned long flags;
+ u32 byte_offset;
+
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
+ dev_kfree_skb_any(skb);
+ netdev_err(dev, "tx ring full\n");
+ netif_tx_stop_queue(txq);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* dma needs to start on a 16 byte aligned address */
+ byte_offset = CPHYSADDR(skb->data) % 16;
+ ch->skb[ch->dma.desc] = skb;
+
+ dev->trans_start = jiffies;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len,
+ DMA_TO_DEVICE)) - byte_offset;
+ wmb();
+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
+ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
+ netif_tx_stop_queue(txq);
+
+ return NETDEV_TX_OK;
+}
+
+static int
+ltq_etop_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int ret = eth_change_mtu(dev, new_mtu);
+
+ if (!ret) {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu,
+ LTQ_ETOP_IGPLEN);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ return ret;
+}
+
+static int
+ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(rq);
+
+ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/
+ return phy_mii_ioctl(priv->phydev, data, cmd);
+}
+
+static int
+ltq_etop_set_mac_address(struct net_device *dev, void *p)
+{
+ int ret = eth_mac_addr(dev, p);
+
+ if (!ret) {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ /* store the mac for the unicast filter */
+ spin_lock_irqsave(&priv->lock, flags);
+ ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0);
+ ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16,
+ LTQ_ETOP_MAC_DA1);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ return ret;
+}
+
+static void
+ltq_etop_set_multicast_list(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ /* ensure that the unicast filter is not enabled in promiscious mode */
+ spin_lock_irqsave(&priv->lock, flags);
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI))
+ ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0);
+ else
+ ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u16
+ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ /* we are currently only using the first queue */
+ return 0;
+}
+
+static int
+ltq_etop_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct sockaddr mac;
+ int err;
+
+ ether_setup(dev);
+ dev->watchdog_timeo = 10 * HZ;
+ err = ltq_etop_hw_init(dev);
+ if (err)
+ goto err_hw;
+ ltq_etop_change_mtu(dev, 1500);
+
+ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
+ if (!is_valid_ether_addr(mac.sa_data)) {
+ pr_warn("etop: invalid MAC, using random\n");
+ random_ether_addr(mac.sa_data);
+ }
+
+ err = ltq_etop_set_mac_address(dev, &mac);
+ if (err)
+ goto err_netdev;
+ ltq_etop_set_multicast_list(dev);
+ err = ltq_etop_mdio_init(dev);
+ if (err)
+ goto err_netdev;
+ return 0;
+
+err_netdev:
+ unregister_netdev(dev);
+ free_netdev(dev);
+err_hw:
+ ltq_etop_hw_exit(dev);
+ return err;
+}
+
+static void
+ltq_etop_tx_timeout(struct net_device *dev)
+{
+ int err;
+
+ ltq_etop_hw_exit(dev);
+ err = ltq_etop_hw_init(dev);
+ if (err)
+ goto err_hw;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ return;
+
+err_hw:
+ ltq_etop_hw_exit(dev);
+ netdev_err(dev, "failed to restart etop after TX timeout\n");
+}
+
+static const struct net_device_ops ltq_eth_netdev_ops = {
+ .ndo_open = ltq_etop_open,
+ .ndo_stop = ltq_etop_stop,
+ .ndo_start_xmit = ltq_etop_tx,
+ .ndo_change_mtu = ltq_etop_change_mtu,
+ .ndo_do_ioctl = ltq_etop_ioctl,
+ .ndo_set_mac_address = ltq_etop_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = ltq_etop_set_multicast_list,
+ .ndo_select_queue = ltq_etop_select_queue,
+ .ndo_init = ltq_etop_init,
+ .ndo_tx_timeout = ltq_etop_tx_timeout,
+};
+
+static int __init
+ltq_etop_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct ltq_etop_priv *priv;
+ struct resource *res;
+ int err;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get etop resource\n");
+ err = -ENOENT;
+ goto err_out;
+ }
+
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request etop resource\n");
+ err = -EBUSY;
+ goto err_out;
+ }
+
+ ltq_etop_membase = devm_ioremap_nocache(&pdev->dev,
+ res->start, resource_size(res));
+ if (!ltq_etop_membase) {
+ dev_err(&pdev->dev, "failed to remap etop engine %d\n",
+ pdev->id);
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
+ strcpy(dev->name, "eth%d");
+ dev->netdev_ops = &ltq_eth_netdev_ops;
+ dev->ethtool_ops = &ltq_etop_ethtool_ops;
+ priv = netdev_priv(dev);
+ priv->res = res;
+ priv->pldata = dev_get_platdata(&pdev->dev);
+ priv->netdev = dev;
+ spin_lock_init(&priv->lock);
+
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ if (IS_TX(i))
+ netif_napi_add(dev, &priv->ch[i].napi,
+ ltq_etop_poll_tx, 8);
+ else if (IS_RX(i))
+ netif_napi_add(dev, &priv->ch[i].napi,
+ ltq_etop_poll_rx, 32);
+ priv->ch[i].netdev = dev;
+ }
+
+ err = register_netdev(dev);
+ if (err)
+ goto err_free;
+
+ platform_set_drvdata(pdev, dev);
+ return 0;
+
+err_free:
+ kfree(dev);
+err_out:
+ return err;
+}
+
+static int __devexit
+ltq_etop_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ if (dev) {
+ netif_tx_stop_all_queues(dev);
+ ltq_etop_hw_exit(dev);
+ ltq_etop_mdio_cleanup(dev);
+ unregister_netdev(dev);
+ }
+ return 0;
+}
+
+static struct platform_driver ltq_mii_driver = {
+ .remove = __devexit_p(ltq_etop_remove),
+ .driver = {
+ .name = "ltq_etop",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_ltq_etop(void)
+{
+ int ret = platform_driver_probe(&ltq_mii_driver, ltq_etop_probe);
+
+ if (ret)
+ pr_err("ltq_etop: Error registering platfom driver!");
+ return ret;
+}
+
+static void __exit
+exit_ltq_etop(void)
+{
+ platform_driver_unregister(&ltq_mii_driver);
+}
+
+module_init(init_ltq_etop);
+module_exit(exit_ltq_etop);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC ETOP");
+MODULE_LICENSE("GPL");

View file

@ -0,0 +1,50 @@
From 72a9b536ef81f06bb8042abee0410458f5df93d2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 6 May 2011 00:10:02 +0200
Subject: [PATCH 12/13] MIPS: Lantiq: Add etop board support
Register the etop platform device inside the machtype specific init code.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2356/
Patchwork: https://patchwork.linux-mips.org/patch/2370/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
arch/mips/lantiq/xway/mach-easy50712.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
index e5e7e09..ea5027b 100644
--- a/arch/mips/lantiq/xway/mach-easy50712.c
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
@@ -12,6 +12,7 @@
#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>
@@ -55,11 +56,16 @@ static struct ltq_pci_data ltq_pci_data = {
},
};
+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(&ltq_pci_data);
+ ltq_register_etop(&ltq_eth_data);
}
MIPS_MACHINE(LTQ_MACH_EASY50712,
--
1.7.2.3

View file

@ -0,0 +1,310 @@
From 3466449c8f455da0cb646231602e6af16190f592 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 5 May 2011 23:00:23 +0200
Subject: [PATCH 13/13] MIPS: Lantiq: Add watchdog support
This patch adds the driver for the watchdog found inside the Lantiq SoC family.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: Wim Van Sebroeck <wim@iguana.be>
Cc: linux-mips@linux-mips.org
Cc: linux-watchdog@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/2327/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
drivers/watchdog/Kconfig | 6 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/lantiq_wdt.c | 261 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 268 insertions(+), 0 deletions(-)
create mode 100644 drivers/watchdog/lantiq_wdt.c
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -850,6 +850,12 @@
help
Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
+config LANTIQ_WDT
+ tristate "Lantiq SoC watchdog"
+ depends on LANTIQ
+ help
+ Hardware driver for the Lantiq SoC Watchdog Timer.
+
# PARISC Architecture
# POWERPC Architecture
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -113,6 +113,7 @@
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
+obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
# PARISC Architecture
--- /dev/null
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -0,0 +1,261 @@
+/*
+ * 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>
+ * Based on EP93xx wdt driver
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <lantiq.h>
+
+/* Section 3.4 of the datasheet
+ * The password sequence protects the WDT control register from unintended
+ * write actions, which might cause malfunction of the WDT.
+ *
+ * essentially the following two magic passwords need to be written to allow
+ * IO access to the WDT core
+ */
+#define LTQ_WDT_PW1 0x00BE0000
+#define LTQ_WDT_PW2 0x00DC0000
+
+#define LTQ_WDT_CR 0x0 /* watchdog control register */
+#define LTQ_WDT_SR 0x8 /* watchdog status register */
+
+#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */
+#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */
+#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */
+ /* divider to 0x40000 */
+#define LTQ_WDT_DIVIDER 0x40000
+#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static void __iomem *ltq_wdt_membase;
+static unsigned long ltq_io_region_clk_rate;
+
+static unsigned long ltq_wdt_bootstatus;
+static unsigned long ltq_wdt_in_use;
+static int ltq_wdt_timeout = 30;
+static int ltq_wdt_ok_to_close;
+
+static void
+ltq_wdt_enable(void)
+{
+ ltq_wdt_timeout = ltq_wdt_timeout *
+ (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
+ if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
+ ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
+
+ /* write the first password magic */
+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
+ /* write the second magic plus the configuration and new timeout */
+ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
+ LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
+}
+
+static void
+ltq_wdt_disable(void)
+{
+ /* write the first password magic */
+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
+ /* write the second password magic with no config
+ * this turns the watchdog off
+ */
+ ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
+}
+
+static ssize_t
+ltq_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ ltq_wdt_ok_to_close = 0;
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ ltq_wdt_ok_to_close = 1;
+ else
+ ltq_wdt_ok_to_close = 0;
+ }
+ }
+ ltq_wdt_enable();
+ }
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+ WDIOF_CARDRESET,
+ .identity = "ltq_wdt",
+};
+
+static long
+ltq_wdt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int __user *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(ltq_wdt_timeout, (int __user *)arg);
+ if (!ret)
+ ltq_wdt_enable();
+ /* intentional drop through */
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(ltq_wdt_timeout, (int __user *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ ltq_wdt_enable();
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int
+ltq_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &ltq_wdt_in_use))
+ return -EBUSY;
+ ltq_wdt_in_use = 1;
+ ltq_wdt_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static int
+ltq_wdt_release(struct inode *inode, struct file *file)
+{
+ if (ltq_wdt_ok_to_close)
+ ltq_wdt_disable();
+ else
+ pr_err("ltq_wdt: watchdog closed without warning\n");
+ ltq_wdt_ok_to_close = 0;
+ clear_bit(0, &ltq_wdt_in_use);
+
+ return 0;
+}
+
+static const struct file_operations ltq_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = ltq_wdt_write,
+ .unlocked_ioctl = ltq_wdt_ioctl,
+ .open = ltq_wdt_open,
+ .release = ltq_wdt_release,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice ltq_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ltq_wdt_fops,
+};
+
+static int __init
+ltq_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct clk *clk;
+
+ if (!res) {
+ dev_err(&pdev->dev, "cannot obtain I/O memory region");
+ return -ENOENT;
+ }
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "cannot request I/O memory region");
+ return -EBUSY;
+ }
+ ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ltq_wdt_membase) {
+ dev_err(&pdev->dev, "cannot remap I/O memory region\n");
+ return -ENOMEM;
+ }
+
+ /* we do not need to enable the clock as it is always running */
+ clk = clk_get(&pdev->dev, "io");
+ WARN_ON(!clk);
+ ltq_io_region_clk_rate = clk_get_rate(clk);
+ clk_put(clk);
+
+ if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST)
+ ltq_wdt_bootstatus = WDIOF_CARDRESET;
+
+ return misc_register(&ltq_wdt_miscdev);
+}
+
+static int __devexit
+ltq_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&ltq_wdt_miscdev);
+
+ if (ltq_wdt_membase)
+ iounmap(ltq_wdt_membase);
+
+ return 0;
+}
+
+
+static struct platform_driver ltq_wdt_driver = {
+ .remove = __devexit_p(ltq_wdt_remove),
+ .driver = {
+ .name = "ltq_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init
+init_ltq_wdt(void)
+{
+ return platform_driver_probe(&ltq_wdt_driver, ltq_wdt_probe);
+}
+
+static void __exit
+exit_ltq_wdt(void)
+{
+ return platform_driver_unregister(&ltq_wdt_driver);
+}
+
+module_init(init_ltq_wdt);
+module_exit(exit_ltq_wdt);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);

View file

@ -12406,18 +12406,6 @@
+extern int sys_gpe_hw_is_activated(u32 mask);
+
+#endif /* __FALCON_SYSCTRL_H */
--- a/arch/mips/include/asm/mach-lantiq/lantiq_regs.h
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_regs.h
@@ -12,6 +12,9 @@
#ifdef CONFIG_SOC_LANTIQ_XWAY
#include <xway.h>
#include <xway_irq.h>
+#elif defined(CONFIG_SOC_LANTIQ_FALCON)
+#include <lantiq_falcon.h>
+#include <lantiq_falcon_irq.h>
#endif
#endif
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/falcon/cpu-feature-overrides.h
@@ -0,0 +1,58 @@

View file

@ -1,7 +1,7 @@
--- /dev/null
+++ b/arch/mips/lantiq/falcon/Kconfig
@@ -0,0 +1,11 @@
+if SOC_LANTIQ_FALCON
+if SOC_FALCON
+
+menu "Mips Machine"
+
@ -20,7 +20,7 @@
+obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
--- /dev/null
+++ b/arch/mips/lantiq/falcon/clk-falcon.c
@@ -0,0 +1,46 @@
@@ -0,0 +1,48 @@
+/*
+ * 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
@ -38,35 +38,37 @@
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <falcon.h>
+#include <lantiq_soc.h>
+
+#include <falcon/sys1_reg.h>
+#include <falcon.h>
+#include <gpon_reg_base.h>
+#include <sys1_reg.h>
+
+static struct gpon_reg_sys1 * const pSYS1 = (struct gpon_reg_sys1 *)GPON_SYS1_BASE;
+
+unsigned int
+lq_get_io_region_clock(void)
+ltq_get_io_region_clock(void)
+{
+ return 200000000; /* 200 MHz */
+}
+EXPORT_SYMBOL(lq_get_io_region_clock);
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int
+lq_get_cpu_hz(void)
+ltq_get_cpu_hz(void)
+{
+ if ((lq_r32(&pSYS1->cpu0cc) & CPU0CC_CPUDIV) == CPU0CC_CPUDIV_SELFHALF)
+ if ((ltq_r32(&pSYS1->cpu0cc) & CPU0CC_CPUDIV) == CPU0CC_CPUDIV_SELFHALF)
+ return 200000000; /* 200 MHz */
+ else
+ return 400000000; /* 400 MHz */
+}
+EXPORT_SYMBOL(lq_get_cpu_hz);
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int
+lq_get_fpi_hz(void)
+ltq_get_fpi_hz(void)
+{
+ return 100000000;
+}
+EXPORT_SYMBOL(lq_get_fpi_hz);
+EXPORT_SYMBOL(ltq_get_fpi_hz);
--- /dev/null
+++ b/arch/mips/lantiq/falcon/devices.c
@@ -0,0 +1,180 @@
@ -101,15 +103,15 @@
+
+#include "devices.h"
+
+unsigned char lq_ethaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+EXPORT_SYMBOL(lq_ethaddr);
+unsigned char ltq_ethaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+EXPORT_SYMBOL(ltq_ethaddr);
+
+static int __init
+falcon_set_ethaddr(char *str)
+{
+ sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &lq_ethaddr[0], &lq_ethaddr[1], &lq_ethaddr[2],
+ &lq_ethaddr[3], &lq_ethaddr[4], &lq_ethaddr[5]);
+ &ltq_ethaddr[0], &ltq_ethaddr[1], &ltq_ethaddr[2],
+ &ltq_ethaddr[3], &ltq_ethaddr[4], &ltq_ethaddr[5]);
+ return 0;
+}
+__setup("ethaddr=", falcon_set_ethaddr);
@ -135,11 +137,11 @@
+{
+ switch (port) {
+ case 0:
+ platform_device_register_simple("lq_asc", 0,
+ platform_device_register_simple("ltq_asc", 0,
+ falcon_asc0_resources, ARRAY_SIZE(falcon_asc0_resources));
+ break;
+ case 1:
+ platform_device_register_simple("lq_asc", 1,
+ platform_device_register_simple("ltq_asc", 1,
+ falcon_asc1_resources, ARRAY_SIZE(falcon_asc1_resources));
+ break;
+ default:
@ -148,37 +150,37 @@
+}
+
+/* nor flash */
+static struct resource lq_nor_resource =
+ MEM_RES("nor",LQ_FLASH_START,LQ_FLASH_START + LQ_FLASH_MAX - 1);
+static struct resource ltq_nor_resource =
+ MEM_RES("nor",LTQ_FLASH_START,LTQ_FLASH_START + LTQ_FLASH_MAX - 1);
+
+static struct platform_device lq_nor = {
+ .name = "lq_nor",
+ .resource = &lq_nor_resource,
+static struct platform_device ltq_nor = {
+ .name = "ltq_nor",
+ .resource = &ltq_nor_resource,
+ .num_resources = 1,
+};
+
+void __init falcon_register_nor(struct physmap_flash_data *data)
+{
+ lq_nor.dev.platform_data = data;
+ platform_device_register(&lq_nor);
+ ltq_nor.dev.platform_data = data;
+ platform_device_register(&ltq_nor);
+}
+
+/* spi flash */
+static struct resource lq_spi_resources[] = {
+static struct resource ltq_spi_resources[] = {
+ MEM_RES("ebu", GPON_EBU_BASE, GPON_EBU_END),
+ MEM_RES("sys1", GPON_SYS1_BASE, GPON_SYS1_END)
+};
+
+static struct platform_device lq_spi = {
+static struct platform_device ltq_spi = {
+ .name = "falcon_spi",
+ .resource = lq_spi_resources,
+ .num_resources = ARRAY_SIZE(lq_spi_resources)
+ .resource = ltq_spi_resources,
+ .num_resources = ARRAY_SIZE(ltq_spi_resources)
+};
+
+void __init falcon_register_spi_flash(struct spi_board_info *data)
+{
+ spi_register_board_info(data, 1);
+ platform_device_register(&lq_spi);
+ platform_device_register(&ltq_spi);
+}
+
+/* watchdog */
@ -187,7 +189,7 @@
+
+void __init falcon_register_wdt(void)
+{
+ platform_device_register_simple("lq_wdt", 0, &falcon_wdt_resource, 1);
+ platform_device_register_simple("ltq_wdt", 0, &falcon_wdt_resource, 1);
+}
+
+/* gpio */
@ -248,7 +250,7 @@
+
+void __init falcon_register_crypto(void)
+{
+ platform_device_register_simple("lq_falcon_deu", 0, NULL, 0);
+ platform_device_register_simple("ltq_falcon_deu", 0, NULL, 0);
+}
--- /dev/null
+++ b/arch/mips/lantiq/falcon/devices.h
@ -276,7 +278,7 @@
+#endif
--- /dev/null
+++ b/arch/mips/lantiq/falcon/prom.c
@@ -0,0 +1,44 @@
@@ -0,0 +1,52 @@
+/*
+ * 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
@ -291,6 +293,8 @@
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include <falcon.h>
+
+#include <falcon/gpon_reg_base.h>
@ -304,10 +308,16 @@
+#define SOC_FALCON "Falcon"
+
+void __init
+lq_soc_detect(struct lq_soc_info *i)
+ltq_soc_setup(void)
+{
+ i->partnum = (lq_r32(&pSTATUS->chipid) & STATUS_CHIPID_PARTNR_MASK) >> STATUS_CHIPID_PARTNR_OFFSET;
+ i->rev = (lq_r32(&pSTATUS->chipid) & STATUS_CHIPID_VERSION_MASK) >> STATUS_CHIPID_VERSION_OFFSET;
+ /* not used */
+}
+
+void __init
+ltq_soc_detect(struct ltq_soc_info *i)
+{
+ i->partnum = (ltq_r32(&pSTATUS->chipid) & STATUS_CHIPID_PARTNR_MASK) >> STATUS_CHIPID_PARTNR_OFFSET;
+ i->rev = (ltq_r32(&pSTATUS->chipid) & STATUS_CHIPID_VERSION_MASK) >> STATUS_CHIPID_VERSION_OFFSET;
+ switch (i->partnum)
+ {
+ case SOC_ID_FALCON:
@ -1173,7 +1183,7 @@
+module_exit(falcon_gpio_exit);
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon.h
@@ -0,0 +1,30 @@
@@ -0,0 +1,16 @@
+/*
+ * 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
@ -1184,29 +1194,15 @@
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifdef CONFIG_SOC_LANTIQ_FALCON
+#ifdef CONFIG_SOC_FALCON
+
+#ifndef _LQ_FALCON_H__
+#define _LQ_FALCON_H__
+
+#include <lantiq.h>
+#include <lantiq_soc.h>
+#include <falcon/gpon_reg_base.h>
+
+/*------------ GENERAL */
+#define BOARD_SYSTEM_TYPE "LANTIQ"
+
+/*------------ Chip IDs */
+#define SOC_ID_FALCON 0x01B8
+
+/*------------ SoC Types */
+#define SOC_TYPE_FALCON 0x01
+
+#endif
+
+#endif
--- /dev/null
+++ b/arch/mips/lantiq/falcon/reset.c
@@ -0,0 +1,72 @@
@@ -0,0 +1,80 @@
+/*
+ * 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
@ -1220,6 +1216,7 @@
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <asm/reboot.h>
+#include <linux/module.h>
+
+#include <falcon.h>
+#include <falcon/gpon_reg_base.h>
@ -1232,18 +1229,25 @@
+#define WDT_PW2 0x00DC0000
+#define WDT_REG_BASE (KSEG1 | 0x1F8803F0)
+
+/* This function is used by the watchdog driver */
+int ltq_reset_cause(void)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ltq_reset_cause);
+
+static void
+lq_machine_restart(char *command)
+ltq_machine_restart(char *command)
+{
+ printk(KERN_NOTICE "System restart\n");
+ local_irq_disable();
+ lq_w32(0, (void*)0xBF200000); /* reset Bootreg RVEC */
+ ltq_w32(0, (void*)0xBF200000); /* reset Bootreg RVEC */
+#if 0
+ lq_w32(RBT_CPU_TRIG, &pSYS1->rbt);
+ ltq_w32(RBT_CPU_TRIG, &pSYS1->rbt);
+#else
+ /* use workaround via watchdog timer */
+ lq_w32(WDT_PW1, (void*)WDT_REG_BASE);
+ lq_w32(WDT_PW2 |
+ ltq_w32(WDT_PW1, (void*)WDT_REG_BASE);
+ ltq_w32(WDT_PW2 |
+ (0x3 << 26) | /* PWL */
+ (0x2 << 24) | /* CLKDIV */
+ (0x1 << 31) | /* enable */
@ -1254,7 +1258,7 @@
+}
+
+static void
+lq_machine_halt(void)
+ltq_machine_halt(void)
+{
+ printk(KERN_NOTICE "System halted.\n");
+ local_irq_disable();
@ -1262,7 +1266,7 @@
+}
+
+static void
+lq_machine_power_off(void)
+ltq_machine_power_off(void)
+{
+ printk(KERN_NOTICE "Please turn off the power now.\n");
+ local_irq_disable();
@ -1272,16 +1276,16 @@
+static int __init
+mips_reboot_setup(void)
+{
+ _machine_restart = lq_machine_restart;
+ _machine_halt = lq_machine_halt;
+ pm_power_off = lq_machine_power_off;
+ _machine_restart = ltq_machine_restart;
+ _machine_halt = ltq_machine_halt;
+ pm_power_off = ltq_machine_power_off;
+ return 0;
+}
+
+arch_initcall(mips_reboot_setup);
--- /dev/null
+++ b/arch/mips/lantiq/falcon/mach-easy98000.c
@@ -0,0 +1,246 @@
@@ -0,0 +1,247 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
@ -1299,7 +1303,8 @@
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/spi/eeprom.h>
+#include <machine.h>
+
+#include "../machtypes.h"
+
+#include "devices.h"
+#include "dev-leds-gpio.h"
@ -1311,7 +1316,7 @@
+#define EASY98000_GPIO_LED_4 13
+#define EASY98000_GPIO_LED_5 14
+
+extern unsigned char lq_ethaddr[6];
+extern unsigned char ltq_ethaddr[6];
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition easy98000_nor_partitions[] =
@ -1420,10 +1425,10 @@
+
+static void __init register_davicom(void)
+{
+ if (!is_valid_ether_addr(lq_ethaddr))
+ if (!is_valid_ether_addr(ltq_ethaddr))
+ random_ether_addr(dm9000_plat_data.dev_addr);
+ else {
+ memcpy(dm9000_plat_data.dev_addr, lq_ethaddr, 6);
+ memcpy(dm9000_plat_data.dev_addr, ltq_ethaddr, 6);
+ /* change to "Locally Administered Address" */
+ dm9000_plat_data.dev_addr[0] |= 0x2;
+ }
@ -1500,7 +1505,7 @@
+ falcon_register_i2c();
+ platform_device_register(&easy98000_i2c_gpio_device);
+ register_davicom();
+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98000_leds_gpio),
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98000_leds_gpio),
+ easy98000_leds_gpio);
+ register_easy98000_cpld_led();
+ falcon_register_crypto();
@ -1689,49 +1694,44 @@
+#endif
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -21,16 +21,16 @@ choice
prompt "SoC Type"
default SOC_LANTIQ_XWAY
-#config SOC_LANTIQ_FALCON
-# bool "FALCON"
-# select SOC_LANTIQ
+config SOC_LANTIQ_FALCON
+ bool "FALCON"
+ select SOC_LANTIQ
config SOC_LANTIQ_XWAY
@@ -16,8 +16,12 @@
bool "XWAY"
select SOC_LANTIQ
select SOC_TYPE_XWAY
select HW_HAS_PCI
+
+config SOC_FALCON
+ bool "FALCON"
endchoice
-#source "arch/mips/lantiq/falcon/Kconfig"
+source "arch/mips/lantiq/falcon/Kconfig"
source "arch/mips/lantiq/xway/Kconfig"
+source "arch/mips/lantiq/falcon/Kconfig"
if EARLY_PRINTK
--- a/arch/mips/include/asm/mach-lantiq/machine.h
+++ b/arch/mips/include/asm/mach-lantiq/machine.h
@@ -5,6 +5,7 @@ enum lantiq_mach_type {
/* FALCON */
LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
+ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
/* XWAY */
endif
--- a/arch/mips/lantiq/Makefile
+++ b/arch/mips/lantiq/Makefile
@@ -1,3 +1,4 @@
obj-y := dev-leds-gpio.o irq.o setup.o clk.o prom.o
@@ -9,3 +9,4 @@
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_SOC_LANTIQ_FALCON) += falcon/
obj-$(CONFIG_SOC_LANTIQ_XWAY) += xway/
obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
+obj-$(CONFIG_SOC_FALCON) += falcon/
--- a/arch/mips/lantiq/Platform
+++ b/arch/mips/lantiq/Platform
@@ -5,4 +5,5 @@
platform-$(CONFIG_LANTIQ) += lantiq/
@@ -6,3 +6,4 @@
cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+cflags-$(CONFIG_SOC_LANTIQ_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
cflags-$(CONFIG_SOC_LANTIQ_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
+cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -15,6 +15,11 @@
LTQ_MACH_GENERIC = 0,
LTQ_MACH_EASY50712, /* Danube evaluation board */
LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
+
+ /* FALCON */
+ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
+ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
+ LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
};
#endif

View file

@ -1,15 +1,16 @@
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -76,5 +76,6 @@
@@ -74,6 +74,7 @@
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
+obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
EXTRA_CFLAGS += -DDEBUG
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -281,6 +281,10 @@
@@ -278,6 +278,10 @@
comment "I2C system bus drivers (mostly embedded / system-on-chip)"

View file

@ -1,9 +1,9 @@
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.
obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o
obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o
@@ -16,6 +16,7 @@
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_FALCON) += spi_falcon.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o
@ -484,14 +484,14 @@
+MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver");
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -169,6 +169,10 @@ config SPI_LM70_LLP
@@ -142,6 +142,10 @@
which interfaces to an LM70 temperature sensor using
a parallel port.
+config SPI_FALCON
+ tristate "Falcon SPI controller support"
+ depends on SOC_LANTIQ_FALCON
+ depends on SOC_FALCON
+
config SPI_MPC52xx
tristate "Freescale MPC52xx SPI (non-PSC) controller support"
depends on PPC_MPC52xx && SPI
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
depends on PPC_MPC52xx && EXPERIMENTAL

View file

@ -44,8 +44,8 @@
+#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c))
+#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012))
+
+#define lq_r16(reg) __raw_readw(reg)
+#define lq_w16(val, reg) __raw_writew(val, reg)
+#define ltq_r16(reg) __raw_readw(reg)
+#define ltq_w16(val, reg) __raw_writew(val, reg)
+
+struct cpld_led_dev {
+ struct led_classdev cdev;
@ -60,12 +60,12 @@
+
+void led_set(u8 mask, u16 *base)
+{
+ lq_w16(lq_r16(base) | mask, base);
+ ltq_w16(ltq_r16(base) | mask, base);
+}
+
+void led_clear(u8 mask, u16 *base)
+{
+ lq_w16(lq_r16(base) & (~mask), base);
+ ltq_w16(ltq_r16(base) & (~mask), base);
+}
+
+void led_blink_clear(u8 mask, u16 *base)

View file

@ -12,7 +12,7 @@
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <machine.h>
+#include "../machtypes.h"
+
+#include "devices.h"
+#include "dev-leds-gpio.h"
@ -22,7 +22,7 @@
+#define EASY98020_GPIO_LED_2 11
+#define EASY98020_GPIO_LED_3 12
+
+extern unsigned char lq_ethaddr[6];
+extern unsigned char ltq_ethaddr[6];
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition easy98020_spi_partitions[] =
@ -89,7 +89,7 @@
+ falcon_register_wdt();
+ falcon_register_i2c();
+ falcon_register_spi_flash(&easy98020_spi_flash_data);
+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio),
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio),
+ easy98020_leds_gpio);
+ falcon_register_crypto();
+}
@ -100,7 +100,7 @@
+ easy98020_init);
--- a/arch/mips/lantiq/falcon/Kconfig
+++ b/arch/mips/lantiq/falcon/Kconfig
@@ -6,6 +6,10 @@ config LANTIQ_MACH_EASY98000
@@ -6,6 +6,10 @@
bool "Easy98000"
default y
@ -113,7 +113,7 @@
endif
--- a/arch/mips/lantiq/falcon/Makefile
+++ b/arch/mips/lantiq/falcon/Makefile
@@ -2,3 +2,4 @@ obj-y := clk-falcon.o devices.o gpio.o p
@@ -2,3 +2,4 @@
obj-y += softdog_vpe.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o

View file

@ -4,7 +4,7 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-gpio.h>
+#include <machine.h>
+#include "../machtypes.h"
+
+#include "devices.h"
+#include "dev-leds-gpio.h"
@ -14,7 +14,7 @@
+#define BOARD_95C3AM1_GPIO_LED_2 12
+#define BOARD_95C3AM1_GPIO_LED_3 13
+
+extern unsigned char lq_ethaddr[6];
+extern unsigned char ltq_ethaddr[6];
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition board_95C3AM1_partitions[] =
@ -95,7 +95,7 @@
+ falcon_register_i2c();
+ falcon_register_spi_flash(&board_95C3AM1_flash_data);
+ platform_device_register(&board_95C3AM1_i2c_gpio_device);
+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio),
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio),
+ board_95C3AM1_leds_gpio);
+ falcon_register_crypto();
+}
@ -104,19 +104,9 @@
+ "95C3AM1",
+ "95C3AM1 Board",
+ board_95C3AM1_init);
--- a/arch/mips/include/asm/mach-lantiq/machine.h
+++ b/arch/mips/include/asm/mach-lantiq/machine.h
@@ -7,6 +7,7 @@ enum lantiq_mach_type {
LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
+ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
/* XWAY */
LANTIQ_MACH_EASY4010, /* Twinpass evalkit */
--- a/arch/mips/lantiq/falcon/Kconfig
+++ b/arch/mips/lantiq/falcon/Kconfig
@@ -10,6 +10,10 @@ config LANTIQ_MACH_EASY98020
@@ -10,6 +10,10 @@
bool "Easy98020"
default y
@ -129,8 +119,18 @@
endif
--- a/arch/mips/lantiq/falcon/Makefile
+++ b/arch/mips/lantiq/falcon/Makefile
@@ -3,3 +3,4 @@ obj-y += softdog_vpe.o
@@ -3,3 +3,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
+obj-$(CONFIG_LANTIQ_MACH_95C3AM1) += mach-95C3AM1.o
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -20,6 +20,7 @@
LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
+ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
};
#endif

View file

@ -1,25 +1,7 @@
--- a/arch/mips/include/asm/mach-lantiq/machine.h
+++ b/arch/mips/include/asm/mach-lantiq/machine.h
@@ -11,4 +11,15 @@
LANTIQ_MACH_EASY4010, /* Twinpass evalkit */
LANTIQ_MACH_EASY50712, /* Danube evalkit */
LANTIQ_MACH_EASY50812, /* AR9 eval board */
+
+ /* Arcadyan */
+ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */
+ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */
+ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */
+ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */
+ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */
+ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */
+ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */
+ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */
+ LANTIQ_MACH_ARV7518PW, /* ASTORIA */
};
--- a/arch/mips/lantiq/xway/Kconfig
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -14,6 +14,10 @@
bool "Easy4010"
@@ -6,6 +6,10 @@
bool "Easy50712 - Danube"
default y
+config LANTIQ_MACH_ARV45XX
@ -31,14 +13,14 @@
endif
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY50812) += mach-easy50812.o
@@ -5,3 +5,4 @@
obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
obj-$(CONFIG_LANTIQ_MACH_EASY4010) += mach-easy4010.o
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
+obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-arv45xx.c
@@ -0,0 +1,537 @@
@@ -0,0 +1,504 @@
+/*
+ * 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
@ -60,12 +42,12 @@
+#include <linux/ath5k_platform.h>
+#include <linux/pci.h>
+
+#include <machine.h>
+
+#include <xway.h>
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+#include "dev-leds-gpio.h"
+#include "dev-dwc_otg.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
@ -164,7 +146,7 @@
+#endif
+};
+
+static struct lq_pci_data lq_pci_data = {
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_EXT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
@ -172,9 +154,8 @@
+ },
+};
+
+static struct lq_eth_data lq_eth_data = {
+ .mii_mode = REV_MII_MODE,
+ .mac = "\xff\xff\xff\xff\xff\xff",
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_RMII,
+};
+
+static struct gpio_led
@ -191,10 +172,10 @@
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:fail", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:voip", .gpio = 32, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs1", .gpio = 33, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs2", .gpio = 34, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxo", .gpio = 35, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:voip", .gpio = 72, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs1", .gpio = 73, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxs2", .gpio = 74, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_button
@ -212,13 +193,13 @@
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, },
+ { .name = "soc:blue:voip", .gpio = 32, .active_low = 1, },
+ { .name = "soc:blue:fxs1", .gpio = 33, .active_low = 1, },
+ { .name = "soc:blue:fxs2", .gpio = 34, .active_low = 1, },
+ { .name = "soc:blue:fxo", .gpio = 35, .active_low = 1, },
+ { .name = "soc:blue:voice", .gpio = 36, .active_low = 1, },
+ { .name = "soc:blue:usb", .gpio = 37, .active_low = 1, },
+ { .name = "soc:blue:wlan", .gpio = 38, .active_low = 1, },
+ { .name = "soc:blue:voip", .gpio = 72, .active_low = 1, },
+ { .name = "soc:blue:fxs1", .gpio = 73, .active_low = 1, },
+ { .name = "soc:blue:fxs2", .gpio = 74, .active_low = 1, },
+ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, },
+ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, },
+ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, },
+ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, },
+};
+
+static struct gpio_led
@ -229,15 +210,15 @@
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs1", .gpio = 32, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs2", .gpio = 33, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wps", .gpio = 34, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxo", .gpio = 35, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:voice", .gpio = 36, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:usb", .gpio = 37, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 38, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:internet", .gpio = 40, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:internet", .gpio = 41, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs1", .gpio = 72, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxs2", .gpio = 73, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wps", .gpio = 74, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:internet", .gpio = 80, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:internet", .gpio = 81, .active_low = 1, .default_trigger = "default-on" },
+};
+
+static struct gpio_led
@ -255,17 +236,17 @@
+ { .name = "soc:red:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:wps", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:fxo", .gpio = 35, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:voice", .gpio = 36, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 37, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 38, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan1", .gpio = 39, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 40, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan1", .gpio = 41, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth1", .gpio = 43, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth2", .gpio = 44, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth3", .gpio = 45, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth4", .gpio = 46, .active_low = 1, .default_trigger = "default-on", },
+ { .name = "soc:red:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:red:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:wlan1", .gpio = 79, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan", .gpio = 80, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:blue:wlan1", .gpio = 81, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth1", .gpio = 83, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth2", .gpio = 84, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth3", .gpio = 85, .active_low = 1, .default_trigger = "default-on" },
+ { .name = "soc:green:eth4", .gpio = 86, .active_low = 1, .default_trigger = "default-on", },
+};
+
+static struct gpio_button
@ -295,27 +276,27 @@
+arv45xx_register_ethernet(void)
+{
+#define ARV45XX_BRN_MAC 0x3f0016
+ memcpy_fromio(lq_eth_data.mac,
+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ lq_register_ethernet(&lq_eth_data);
+ memcpy_fromio(&ltq_eth_data.mac,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+static void
+arv75xx_register_ethernet(void)
+{
+#define ARV75XX_BRN_MAC 0x7f0016
+ memcpy_fromio(lq_eth_data.mac,
+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV75XX_BRN_MAC), 6);
+ lq_register_ethernet(&lq_eth_data);
+ memcpy_fromio(&ltq_eth_data.mac,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV75XX_BRN_MAC), 6);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+static void
+bewan_register_ethernet(void)
+{
+#define BEWAN_BRN_MAC 0x3f0014
+ memcpy_fromio(lq_eth_data.mac,
+ (void *)KSEG1ADDR(LQ_FLASH_START + BEWAN_BRN_MAC), 6);
+ lq_register_ethernet(&lq_eth_data);
+ memcpy_fromio(&ltq_eth_data.mac,
+ (void *)KSEG1ADDR(LTQ_FLASH_START + BEWAN_BRN_MAC), 6);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+static u16 arv45xx_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
@ -337,10 +318,10 @@
+ u32 *p = (u32*)arv45xx_ath5k_eeprom_data;
+
+ memcpy_fromio(eeprom_mac,
+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
+ eeprom_mac[5]++;
+ memcpy_fromio(arv45xx_ath5k_eeprom_data,
+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS);
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS);
+ // swap eeprom bytes
+ for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS>>1; i++){
+ //arv4518_ath5k_eeprom_data[i] = ((eeprom_data[i]&0xff)<<8)|((eeprom_data[i]&0xff00)>>8);
@ -356,19 +337,15 @@
+ }
+ arv45xx_ath5k_platform_data.eeprom_data = arv45xx_ath5k_eeprom_data;
+ arv45xx_ath5k_platform_data.macaddr = eeprom_mac;
+ lqpci_plat_dev_init = arv45xx_pci_plat_dev_init;
+ //lqpci_plat_dev_init = arv45xx_pci_plat_dev_init;
+}
+
+static void __init
+arv3527p_init(void)
+{
+ lq_register_gpio();
+ lq_register_gpio_stp();
+ //lq_register_gpio_leds(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_register_wdt();
+ ltq_register_gpio_stp();
+ //ltq_add_device_leds_gpio(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio));
+ ltq_register_nor(&arv45xx_flash_data);
+ arv45xx_register_ethernet();
+}
+
@ -380,17 +357,13 @@
+static void __init
+arv4510pw_init(void)
+{
+ lq_register_gpio();
+ lq_register_gpio_stp();
+ lq_register_gpio_leds(arv4510pw_leds_gpio, ARRAY_SIZE(arv4510pw_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv4510_flash_data);
+ lq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31);
+ lq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26);
+ lq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2;
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ ltq_register_gpio_stp();
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4510pw_leds_gpio), arv4510pw_leds_gpio);
+ ltq_register_nor(&arv4510_flash_data);
+ ltq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31);
+ ltq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26);
+ ltq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2;
+ ltq_register_pci(&ltq_pci_data);
+ bewan_register_ethernet();
+}
+
@ -406,17 +379,13 @@
+#define ARV4518PW_USB 14
+#define ARV4518PW_SWITCH_RESET 13
+
+ lq_register_gpio();
+ lq_register_gpio_ebu(ARV4518PW_EBU);
+ lq_register_gpio_leds(arv4518pw_leds_gpio, ARRAY_SIZE(arv4518pw_leds_gpio));
+ lq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_pci_data.gpio = PCI_GNT2 | PCI_REQ2;
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ lq_register_madwifi_eep();
+ ltq_register_gpio_ebu(ARV4518PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4518pw_leds_gpio), arv4518pw_leds_gpio);
+ ltq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons));
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2;
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_madwifi_eep();
+ xway_register_dwc(ARV4518PW_USB);
+ arv45xx_register_ethernet();
+ arv45xx_register_ath5k();
@ -436,17 +405,13 @@
+{
+#define ARV4520PW_EBU 0x400
+#define ARV4520PW_USB 28
+#define ARV4520PW_SWITCH_RESET 42
+#define ARV4520PW_SWITCH_RESET 82
+
+ lq_register_gpio();
+ lq_register_gpio_ebu(ARV4520PW_EBU);
+ lq_register_gpio_leds(arv4520pw_leds_gpio, ARRAY_SIZE(arv4520pw_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ lq_register_tapi();
+ ltq_register_gpio_ebu(ARV4520PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4520pw_leds_gpio), arv4520pw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_tapi();
+ arv45xx_register_ethernet();
+ xway_register_dwc(ARV4520PW_USB);
+
@ -465,18 +430,14 @@
+#define ARV452CPW_EBU 0x77f
+#define ARV452CPW_USB 28
+#define ARV452CPW_RELAY1 31
+#define ARV452CPW_RELAY2 39
+#define ARV452CPW_SWITCH_RESET 42
+#define ARV452CPW_RELAY2 79
+#define ARV452CPW_SWITCH_RESET 82
+
+ lq_register_gpio();
+ lq_register_gpio_ebu(ARV452CPW_EBU);
+ lq_register_gpio_leds(arv452cpw_leds_gpio, ARRAY_SIZE(arv452cpw_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ lq_register_madwifi_eep();
+ ltq_register_gpio_ebu(ARV452CPW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv452cpw_leds_gpio), arv452cpw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_madwifi_eep();
+ xway_register_dwc(ARV452CPW_USB);
+ arv45xx_register_ethernet();
+ arv45xx_register_ath5k();
@ -502,16 +463,12 @@
+static void __init
+arv4525pw_init(void)
+{
+ lq_register_gpio();
+ lq_register_gpio_leds(arv4525pw_leds_gpio, ARRAY_SIZE(arv4525pw_leds_gpio));
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_nor(&arv45xx_flash_data);
+ lq_pci_data.clock = PCI_CLOCK_INT;
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ lq_register_madwifi_eep();
+ lq_eth_data.mii_mode = MII_MODE;
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4525pw_leds_gpio), arv4525pw_leds_gpio);
+ ltq_register_nor(&arv45xx_flash_data);
+ ltq_pci_data.clock = PCI_CLOCK_INT;
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_madwifi_eep();
+ ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII;
+ arv45xx_register_ethernet();
+}
+
@ -526,16 +483,12 @@
+#define ARV7518PW_EBU 0x2
+#define ARV7518PW_USB 14
+
+ lq_register_gpio();
+ lq_register_gpio_ebu(ARV7518PW_EBU);
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_gpio_leds(arv7518pw_leds_gpio, ARRAY_SIZE(arv7518pw_leds_gpio));
+ lq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons));
+ lq_register_nor(&arv75xx_flash_data);
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ lq_register_tapi();
+ ltq_register_gpio_ebu(ARV7518PW_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv7518pw_leds_gpio), arv7518pw_leds_gpio);
+ ltq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons));
+ ltq_register_nor(&arv75xx_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_tapi();
+ xway_register_dwc(ARV7518PW_USB);
+ arv75xx_register_ethernet();
+ //arv7518_register_ath9k(mac);
@ -550,20 +503,16 @@
+arv752dpw22_init(void)
+{
+#define ARV752DPW22_EBU 0x2
+#define ARV752DPW22_USB 32
+#define ARV752DPW22_RELAY 33
+#define ARV752DPW22_USB 72
+#define ARV752DPW22_RELAY 73
+
+ lq_register_gpio();
+ lq_register_gpio_ebu(ARV752DPW22_EBU);
+ lq_register_asc(0);
+ lq_register_asc(1);
+ lq_register_gpio_leds(arv752dpw22_leds_gpio, ARRAY_SIZE(arv752dpw22_leds_gpio));
+ lq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons));
+ lq_register_nor(&arv75xx_flash_data);
+ lq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31);
+ lq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2;
+ lq_register_pci(&lq_pci_data);
+ lq_register_wdt();
+ ltq_register_gpio_ebu(ARV752DPW22_EBU);
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv752dpw22_leds_gpio), arv752dpw22_leds_gpio);
+ ltq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons));
+ ltq_register_nor(&arv75xx_flash_data);
+ ltq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31);
+ ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2;
+ ltq_register_pci(&ltq_pci_data);
+ xway_register_dwc(ARV752DPW22_USB);
+ arv75xx_register_ethernet();
+
@ -576,3 +525,23 @@
+ "ARV752DPW22",
+ "ARV752DPW22 - Arcor A803",
+ arv752dpw22_init);
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -21,6 +21,17 @@
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
+
+ /* Arcadyan */
+ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */
+ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */
+ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */
+ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */
+ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */
+ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */
+ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */
+ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */
+ LANTIQ_MACH_ARV7518PW, /* ASTORIA */
};
#endif

View file

@ -1,6 +1,6 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -63,6 +63,10 @@ config MTD_ROOTFS_SPLIT
@@ -63,6 +63,10 @@
depends on MTD_PARTITIONS
default y
@ -13,7 +13,7 @@
depends on MTD_PARTITIONS
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -722,6 +722,82 @@ static int refresh_rootfs_split(struct m
@@ -724,6 +724,82 @@
}
#endif /* CONFIG_MTD_ROOTFS_SPLIT */
@ -96,7 +96,7 @@
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
@@ -746,6 +822,17 @@ int add_mtd_partitions(struct mtd_info *
@@ -748,6 +824,17 @@
if (!slave)
return -ENOMEM;

View file

@ -0,0 +1,42 @@
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -52,6 +52,8 @@
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
+EXPORT_SYMBOL(_dma_cache_wback);
+EXPORT_SYMBOL(_dma_cache_inv);
#endif /* CONFIG_DMA_NONCOHERENT */
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -152,7 +152,7 @@
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
static const char *const class_name[] =
- {"off","UBR","CBR","VBR","ABR"};
+ {"off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"};
static const char *const aal_name[] = {
"---", "1", "2", "3/4", /* 0- 3 */
"???", "5", "???", "???", /* 4- 7 */
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -57,11 +57,17 @@
}
+struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
+EXPORT_SYMBOL(ifx_atm_alloc_tx);
+
static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
{
struct sk_buff *skb;
struct sock *sk = sk_atm(vcc);
+ if (ifx_atm_alloc_tx != NULL)
+ return ifx_atm_alloc_tx(vcc, size);
+
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
sk_wmem_alloc_get(sk), size,

View file

@ -0,0 +1,45 @@
--- a/arch/mips/lantiq/prom.c
+++ b/arch/mips/lantiq/prom.c
@@ -39,6 +39,34 @@
{
}
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
+extern char __image_cmdline[];
+
+static void __init
+prom_init_image_cmdline(void)
+{
+ char *p = __image_cmdline;
+ int replace = 0;
+
+ if (*p == '-') {
+ replace = 1;
+ p++;
+ }
+
+ if (*p == '\0')
+ return;
+
+ if (replace) {
+ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
+ } else {
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ }
+}
+#else
+static void __init prom_init_image_cmdline(void) { return; }
+#endif
+
static void __init prom_init_cmdline(void)
{
int argc = fw_arg0;
@@ -53,6 +81,7 @@
strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
}
}
+ prom_init_image_cmdline();
}
void __init prom_init(void)

View file

@ -261,18 +261,19 @@
obj-$(CONFIG_PROC_FS) += proc.o
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -107,6 +107,10 @@
@@ -106,7 +106,11 @@
#include <net/xfrm.h>
#include "udp_impl.h"
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
+#include <linux/udp_redirect.h>
+#endif
struct udp_table udp_table;
+
struct udp_table udp_table __read_mostly;
EXPORT_SYMBOL(udp_table);
@@ -784,7 +788,7 @@
int sysctl_udp_mem[3] __read_mostly;
@@ -591,7 +595,7 @@
u8 tos;
int err, is_udplite = IS_UDPLITE(sk);
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
@ -281,7 +282,7 @@
if (len > 0xFFFF)
return -EMSGSIZE;
@@ -946,6 +950,12 @@
@@ -753,6 +757,12 @@
do_append_data:
up->len += ulen;
@ -294,7 +295,7 @@
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,
sizeof(struct udphdr), &ipc, &rt,
@@ -1573,6 +1583,7 @@
@@ -1283,6 +1293,7 @@
struct rtable *rt = skb_rtable(skb);
__be32 saddr, daddr;
struct net *net = dev_net(skb->dev);
@ -302,7 +303,7 @@
/*
* Validate the packet.
@@ -1605,7 +1616,16 @@
@@ -1315,7 +1326,16 @@
sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
if (sk != NULL) {
@ -320,8 +321,8 @@
sock_put(sk);
/* a return value > 0 means to resubmit the input, but
@@ -1902,7 +1922,7 @@
.clear_sk = sk_prot_clear_portaddr_nulls,
@@ -1610,7 +1630,7 @@
#endif
};
EXPORT_SYMBOL(udp_prot);
-

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1844,6 +1844,28 @@
@@ -1653,6 +1653,28 @@
help
IFX included extensions in APRP
@ -31,7 +31,7 @@
depends on MIPS_MT && PROC_FS
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -128,6 +128,13 @@
@@ -129,6 +129,13 @@
EXPORT_SYMBOL(vpe1_wdog_timeout);
#endif
@ -45,7 +45,7 @@
/* grab the likely amount of memory we will need. */
#ifdef CONFIG_MIPS_VPE_LOADER_TOM
#define P_SIZE (2 * 1024 * 1024)
@@ -866,6 +873,65 @@
@@ -867,6 +874,65 @@
/* enable this VPE */
write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
@ -113,7 +113,7 @@
write_vpe_c0_cause(0);
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1347,6 +1347,106 @@
@@ -1348,6 +1348,106 @@
__setup("coherentio", setcoherentio);
#endif
@ -220,7 +220,7 @@
void __cpuinit r4k_cache_init(void)
{
extern void build_clear_page(void);
@@ -1366,6 +1466,78 @@
@@ -1367,6 +1467,78 @@
break;
}

View file

@ -0,0 +1,8 @@
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -1,3 +1,5 @@
+
+
/*
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
*

View file

@ -10,35 +10,27 @@ Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -48,4 +48,13 @@
extern int (*lqpci_plat_dev_init)(struct pci_dev *dev);
@@ -50,4 +50,13 @@
int mii_mode;
};
+
+struct lq_spi_platform_data {
+struct ltq_spi_platform_data {
+ u16 num_chipselect;
+};
+
+struct lq_spi_controller_data {
+struct ltq_spi_controller_data {
+ unsigned gpio;
+};
+
#endif
--- a/arch/mips/include/asm/mach-lantiq/xway/xway.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway.h
@@ -72,6 +72,7 @@
#define LQ_PMU_BASE_ADDR (KSEG1 + 0x1F102000)
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -75,6 +75,7 @@
#define PMU_DMA 0x0020
+#define PMU_SPI 0x0100
#define PMU_USB 0x8041
+#define PMU_SPI 0x0100
#define PMU_LED 0x0800
#define PMU_GPT 0x1000
@@ -105,6 +106,7 @@
/*------------ SSC */
#define LQ_SSC_BASE_ADDR (KSEG1 + 0x1e100800)
+#define LQ_SSC_SIZE 0x100
/*------------ MEI */
#define LQ_MEI_BASE_ADDR (KSEG1 + 0x1E116000)
#define PMU_PPE 0x2000

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
Date: Thu, 3 Mar 2011 20:42:26 +0000 (+0100)
Subject: MIPS: lantiq: Add device register helper for SPI controller and devices
X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=b35b07062b718ece9b9cb7b23b12d83a087eafb0;hp=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90
MIPS: lantiq: Add device register helper for SPI controller and devices
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
---
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/leds.h>
+#include <linux/spi/spi.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
@@ -119,3 +120,28 @@
platform_device_register(&ltq_etop);
}
}
+
+static struct resource ltq_spi_resources[] = {
+ {
+ .start = LTQ_SSC_BASE_ADDR,
+ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(spi_tx, LTQ_SSC_TIR),
+ IRQ_RES(spi_rx, LTQ_SSC_RIR),
+ IRQ_RES(spi_err, LTQ_SSC_EIR),
+};
+
+static struct platform_device ltq_spi = {
+ .name = "ltq-spi",
+ .resource = ltq_spi_resources,
+ .num_resources = ARRAY_SIZE(ltq_spi_resources),
+};
+
+void __init ltq_register_spi(struct ltq_spi_platform_data *pdata,
+ struct spi_board_info const *info, unsigned n)
+{
+ spi_register_board_info(info, n);
+ ltq_spi.dev.platform_data = pdata;
+ platform_device_register(&ltq_spi);
+}

View file

@ -0,0 +1,41 @@
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -121,6 +121,29 @@
}
}
+/* ebu */
+static struct resource ltq_ebu_resource =
+{
+ .name = "gpio_ebu",
+ .start = LTQ_EBU_GPIO_START,
+ .end = LTQ_EBU_GPIO_START + LTQ_EBU_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_ebu =
+{
+ .name = "ltq_ebu",
+ .resource = &ltq_ebu_resource,
+ .num_resources = 1,
+};
+
+void __init
+ltq_register_gpio_ebu(unsigned int value)
+{
+ ltq_ebu.dev.platform_data = (void*) value;
+ platform_device_register(&ltq_ebu);
+}
+
static struct resource ltq_spi_resources[] = {
{
.start = LTQ_SSC_BASE_ADDR,
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -16,5 +16,6 @@
extern void ltq_register_gpio_stp(void);
extern void ltq_register_ase_asc(void);
extern void ltq_register_etop(struct ltq_eth_data *eth);
+extern void ltq_register_gpio_ebu(unsigned int value);
#endif

View file

@ -0,0 +1,28 @@
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -144,6 +144,16 @@
platform_device_register(&ltq_ebu);
}
+/* madwifi */
+int lantiq_emulate_madwifi_eep = 0;
+EXPORT_SYMBOL(lantiq_emulate_madwifi_eep);
+
+void __init
+ltq_register_madwifi_eep(void)
+{
+ lantiq_emulate_madwifi_eep = 1;
+}
+
static struct resource ltq_spi_resources[] = {
{
.start = LTQ_SSC_BASE_ADDR,
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -17,5 +17,6 @@
extern void ltq_register_ase_asc(void);
extern void ltq_register_etop(struct ltq_eth_data *eth);
extern void ltq_register_gpio_ebu(unsigned int value);
+extern void ltq_register_madwifi_eep(void);
#endif

View file

@ -0,0 +1,46 @@
--- a/arch/mips/lantiq/xway/devices.c
+++ b/arch/mips/lantiq/xway/devices.c
@@ -154,6 +154,26 @@
lantiq_emulate_madwifi_eep = 1;
}
+/* gpio buttons */
+static struct gpio_buttons_platform_data ltq_gpio_buttons_platform_data;
+
+static struct platform_device ltq_gpio_buttons_platform_device =
+{
+ .name = "gpio-buttons",
+ .id = 0,
+ .dev = {
+ .platform_data = (void *) &ltq_gpio_buttons_platform_data,
+ },
+};
+
+void __init
+ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt)
+{
+ ltq_gpio_buttons_platform_data.buttons = buttons;
+ ltq_gpio_buttons_platform_data.nbuttons = cnt;
+ platform_device_register(&ltq_gpio_buttons_platform_device);
+}
+
static struct resource ltq_spi_resources[] = {
{
.start = LTQ_SSC_BASE_ADDR,
--- a/arch/mips/lantiq/xway/devices.h
+++ b/arch/mips/lantiq/xway/devices.h
@@ -11,6 +11,7 @@
#include "../devices.h"
#include <linux/phy.h>
+#include <linux/gpio_buttons.h>
extern void ltq_register_gpio(void);
extern void ltq_register_gpio_stp(void);
@@ -18,5 +19,6 @@
extern void ltq_register_etop(struct ltq_eth_data *eth);
extern void ltq_register_gpio_ebu(unsigned int value);
extern void ltq_register_madwifi_eep(void);
+extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt);
#endif

Some files were not shown because too many files have changed in this diff Show more